antigravity-auth 1.6.0 → 1.7.0

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 (258) hide show
  1. package/README.md +79 -41
  2. package/dist/cli.js +2868 -0
  3. package/dist/handler.js +25119 -0
  4. package/dist/index.js +25110 -5
  5. package/package.json +66 -54
  6. package/dist/antigravity/oauth.d.ts +0 -30
  7. package/dist/antigravity/oauth.js +0 -170
  8. package/dist/claude/login.d.ts +0 -7
  9. package/dist/claude/login.js +0 -480
  10. package/dist/claude/menu-helpers.d.ts +0 -22
  11. package/dist/claude/menu-helpers.js +0 -281
  12. package/dist/claude/proxy-manager.d.ts +0 -11
  13. package/dist/claude/proxy-manager.js +0 -129
  14. package/dist/claude/proxy.d.ts +0 -1
  15. package/dist/claude/proxy.js +0 -733
  16. package/dist/constants.d.ts +0 -138
  17. package/dist/constants.js +0 -216
  18. package/dist/hooks/auto-update-checker/cache.d.ts +0 -2
  19. package/dist/hooks/auto-update-checker/cache.js +0 -70
  20. package/dist/hooks/auto-update-checker/checker.d.ts +0 -15
  21. package/dist/hooks/auto-update-checker/checker.js +0 -233
  22. package/dist/hooks/auto-update-checker/constants.d.ts +0 -8
  23. package/dist/hooks/auto-update-checker/constants.js +0 -22
  24. package/dist/hooks/auto-update-checker/index.d.ts +0 -33
  25. package/dist/hooks/auto-update-checker/index.js +0 -121
  26. package/dist/hooks/auto-update-checker/logging.d.ts +0 -2
  27. package/dist/hooks/auto-update-checker/logging.js +0 -8
  28. package/dist/hooks/auto-update-checker/types.d.ts +0 -24
  29. package/dist/hooks/auto-update-checker/types.js +0 -1
  30. package/dist/index.d.ts +0 -6
  31. package/dist/opencode/hooks/auto-update-checker/cache.d.ts +0 -2
  32. package/dist/opencode/hooks/auto-update-checker/cache.js +0 -70
  33. package/dist/opencode/hooks/auto-update-checker/checker.d.ts +0 -15
  34. package/dist/opencode/hooks/auto-update-checker/checker.js +0 -233
  35. package/dist/opencode/hooks/auto-update-checker/constants.d.ts +0 -8
  36. package/dist/opencode/hooks/auto-update-checker/constants.js +0 -22
  37. package/dist/opencode/hooks/auto-update-checker/index.d.ts +0 -33
  38. package/dist/opencode/hooks/auto-update-checker/index.js +0 -121
  39. package/dist/opencode/hooks/auto-update-checker/logging.d.ts +0 -2
  40. package/dist/opencode/hooks/auto-update-checker/logging.js +0 -8
  41. package/dist/opencode/hooks/auto-update-checker/types.d.ts +0 -24
  42. package/dist/opencode/hooks/auto-update-checker/types.js +0 -1
  43. package/dist/opencode/plugin.d.ts +0 -29
  44. package/dist/opencode/plugin.js +0 -2954
  45. package/dist/plugin/accounts.d.ts +0 -173
  46. package/dist/plugin/accounts.js +0 -966
  47. package/dist/plugin/auth.d.ts +0 -20
  48. package/dist/plugin/auth.js +0 -44
  49. package/dist/plugin/cache/index.d.ts +0 -4
  50. package/dist/plugin/cache/index.js +0 -4
  51. package/dist/plugin/cache/signature-cache.d.ts +0 -110
  52. package/dist/plugin/cache/signature-cache.js +0 -347
  53. package/dist/plugin/cache.d.ts +0 -43
  54. package/dist/plugin/cache.js +0 -180
  55. package/dist/plugin/cli.d.ts +0 -26
  56. package/dist/plugin/cli.js +0 -126
  57. package/dist/plugin/config/index.d.ts +0 -15
  58. package/dist/plugin/config/index.js +0 -15
  59. package/dist/plugin/config/loader.d.ts +0 -38
  60. package/dist/plugin/config/loader.js +0 -150
  61. package/dist/plugin/config/models.d.ts +0 -26
  62. package/dist/plugin/config/models.js +0 -95
  63. package/dist/plugin/config/schema.d.ts +0 -144
  64. package/dist/plugin/config/schema.js +0 -458
  65. package/dist/plugin/config/updater.d.ts +0 -76
  66. package/dist/plugin/config/updater.js +0 -205
  67. package/dist/plugin/core/streaming/index.d.ts +0 -2
  68. package/dist/plugin/core/streaming/index.js +0 -2
  69. package/dist/plugin/core/streaming/transformer.d.ts +0 -9
  70. package/dist/plugin/core/streaming/transformer.js +0 -301
  71. package/dist/plugin/core/streaming/types.d.ts +0 -28
  72. package/dist/plugin/core/streaming/types.js +0 -1
  73. package/dist/plugin/debug.d.ts +0 -93
  74. package/dist/plugin/debug.js +0 -375
  75. package/dist/plugin/errors.d.ts +0 -27
  76. package/dist/plugin/errors.js +0 -41
  77. package/dist/plugin/fingerprint.d.ts +0 -69
  78. package/dist/plugin/fingerprint.js +0 -137
  79. package/dist/plugin/image-saver.d.ts +0 -24
  80. package/dist/plugin/image-saver.js +0 -78
  81. package/dist/plugin/logger.d.ts +0 -35
  82. package/dist/plugin/logger.js +0 -67
  83. package/dist/plugin/logging-utils.d.ts +0 -22
  84. package/dist/plugin/logging-utils.js +0 -91
  85. package/dist/plugin/project.d.ts +0 -32
  86. package/dist/plugin/project.js +0 -229
  87. package/dist/plugin/quota.d.ts +0 -34
  88. package/dist/plugin/quota.js +0 -261
  89. package/dist/plugin/recovery/constants.d.ts +0 -21
  90. package/dist/plugin/recovery/constants.js +0 -42
  91. package/dist/plugin/recovery/index.d.ts +0 -11
  92. package/dist/plugin/recovery/index.js +0 -11
  93. package/dist/plugin/recovery/storage.d.ts +0 -23
  94. package/dist/plugin/recovery/storage.js +0 -340
  95. package/dist/plugin/recovery/types.d.ts +0 -115
  96. package/dist/plugin/recovery/types.js +0 -6
  97. package/dist/plugin/recovery.d.ts +0 -60
  98. package/dist/plugin/recovery.js +0 -360
  99. package/dist/plugin/refresh-queue.d.ts +0 -99
  100. package/dist/plugin/refresh-queue.js +0 -235
  101. package/dist/plugin/request-helpers.d.ts +0 -281
  102. package/dist/plugin/request-helpers.js +0 -2200
  103. package/dist/plugin/request.d.ts +0 -110
  104. package/dist/plugin/request.js +0 -1489
  105. package/dist/plugin/rotation.d.ts +0 -182
  106. package/dist/plugin/rotation.js +0 -364
  107. package/dist/plugin/search.d.ts +0 -31
  108. package/dist/plugin/search.js +0 -185
  109. package/dist/plugin/server.d.ts +0 -22
  110. package/dist/plugin/server.js +0 -306
  111. package/dist/plugin/storage.d.ts +0 -136
  112. package/dist/plugin/storage.js +0 -599
  113. package/dist/plugin/stores/signature-store.d.ts +0 -4
  114. package/dist/plugin/stores/signature-store.js +0 -24
  115. package/dist/plugin/thinking-recovery.d.ts +0 -89
  116. package/dist/plugin/thinking-recovery.js +0 -289
  117. package/dist/plugin/token.d.ts +0 -18
  118. package/dist/plugin/token.js +0 -127
  119. package/dist/plugin/transform/claude.d.ts +0 -79
  120. package/dist/plugin/transform/claude.js +0 -256
  121. package/dist/plugin/transform/cross-model-sanitizer.d.ts +0 -34
  122. package/dist/plugin/transform/cross-model-sanitizer.js +0 -224
  123. package/dist/plugin/transform/gemini.d.ts +0 -132
  124. package/dist/plugin/transform/gemini.js +0 -659
  125. package/dist/plugin/transform/index.d.ts +0 -14
  126. package/dist/plugin/transform/index.js +0 -9
  127. package/dist/plugin/transform/model-resolver.d.ts +0 -98
  128. package/dist/plugin/transform/model-resolver.js +0 -320
  129. package/dist/plugin/transform/types.d.ts +0 -110
  130. package/dist/plugin/transform/types.js +0 -1
  131. package/dist/plugin/types.d.ts +0 -95
  132. package/dist/plugin/types.js +0 -1
  133. package/dist/plugin/ui/ansi.d.ts +0 -31
  134. package/dist/plugin/ui/ansi.js +0 -45
  135. package/dist/plugin/ui/auth-menu.d.ts +0 -47
  136. package/dist/plugin/ui/auth-menu.js +0 -199
  137. package/dist/plugin/ui/confirm.d.ts +0 -1
  138. package/dist/plugin/ui/confirm.js +0 -14
  139. package/dist/plugin/ui/select.d.ts +0 -22
  140. package/dist/plugin/ui/select.js +0 -243
  141. package/dist/plugin/version.d.ts +0 -18
  142. package/dist/plugin/version.js +0 -79
  143. package/dist/src/antigravity/oauth.d.ts +0 -30
  144. package/dist/src/antigravity/oauth.js +0 -170
  145. package/dist/src/constants.d.ts +0 -138
  146. package/dist/src/constants.js +0 -216
  147. package/dist/src/hooks/auto-update-checker/cache.d.ts +0 -2
  148. package/dist/src/hooks/auto-update-checker/cache.js +0 -70
  149. package/dist/src/hooks/auto-update-checker/checker.d.ts +0 -15
  150. package/dist/src/hooks/auto-update-checker/checker.js +0 -233
  151. package/dist/src/hooks/auto-update-checker/constants.d.ts +0 -8
  152. package/dist/src/hooks/auto-update-checker/constants.js +0 -22
  153. package/dist/src/hooks/auto-update-checker/index.d.ts +0 -33
  154. package/dist/src/hooks/auto-update-checker/index.js +0 -121
  155. package/dist/src/hooks/auto-update-checker/logging.d.ts +0 -2
  156. package/dist/src/hooks/auto-update-checker/logging.js +0 -8
  157. package/dist/src/hooks/auto-update-checker/types.d.ts +0 -24
  158. package/dist/src/hooks/auto-update-checker/types.js +0 -1
  159. package/dist/src/index.d.ts +0 -6
  160. package/dist/src/index.js +0 -5
  161. package/dist/src/plugin/accounts.d.ts +0 -173
  162. package/dist/src/plugin/accounts.js +0 -966
  163. package/dist/src/plugin/auth.d.ts +0 -20
  164. package/dist/src/plugin/auth.js +0 -44
  165. package/dist/src/plugin/cache/index.d.ts +0 -4
  166. package/dist/src/plugin/cache/index.js +0 -4
  167. package/dist/src/plugin/cache/signature-cache.d.ts +0 -110
  168. package/dist/src/plugin/cache/signature-cache.js +0 -347
  169. package/dist/src/plugin/cache.d.ts +0 -43
  170. package/dist/src/plugin/cache.js +0 -180
  171. package/dist/src/plugin/cli.d.ts +0 -26
  172. package/dist/src/plugin/cli.js +0 -126
  173. package/dist/src/plugin/config/index.d.ts +0 -15
  174. package/dist/src/plugin/config/index.js +0 -15
  175. package/dist/src/plugin/config/loader.d.ts +0 -38
  176. package/dist/src/plugin/config/loader.js +0 -150
  177. package/dist/src/plugin/config/models.d.ts +0 -26
  178. package/dist/src/plugin/config/models.js +0 -95
  179. package/dist/src/plugin/config/schema.d.ts +0 -144
  180. package/dist/src/plugin/config/schema.js +0 -458
  181. package/dist/src/plugin/config/updater.d.ts +0 -76
  182. package/dist/src/plugin/config/updater.js +0 -205
  183. package/dist/src/plugin/core/streaming/index.d.ts +0 -2
  184. package/dist/src/plugin/core/streaming/index.js +0 -2
  185. package/dist/src/plugin/core/streaming/transformer.d.ts +0 -9
  186. package/dist/src/plugin/core/streaming/transformer.js +0 -301
  187. package/dist/src/plugin/core/streaming/types.d.ts +0 -28
  188. package/dist/src/plugin/core/streaming/types.js +0 -1
  189. package/dist/src/plugin/debug.d.ts +0 -93
  190. package/dist/src/plugin/debug.js +0 -375
  191. package/dist/src/plugin/errors.d.ts +0 -27
  192. package/dist/src/plugin/errors.js +0 -41
  193. package/dist/src/plugin/fingerprint.d.ts +0 -69
  194. package/dist/src/plugin/fingerprint.js +0 -137
  195. package/dist/src/plugin/image-saver.d.ts +0 -24
  196. package/dist/src/plugin/image-saver.js +0 -78
  197. package/dist/src/plugin/logger.d.ts +0 -35
  198. package/dist/src/plugin/logger.js +0 -67
  199. package/dist/src/plugin/logging-utils.d.ts +0 -22
  200. package/dist/src/plugin/logging-utils.js +0 -91
  201. package/dist/src/plugin/project.d.ts +0 -32
  202. package/dist/src/plugin/project.js +0 -229
  203. package/dist/src/plugin/quota.d.ts +0 -34
  204. package/dist/src/plugin/quota.js +0 -261
  205. package/dist/src/plugin/recovery/constants.d.ts +0 -21
  206. package/dist/src/plugin/recovery/constants.js +0 -42
  207. package/dist/src/plugin/recovery/index.d.ts +0 -11
  208. package/dist/src/plugin/recovery/index.js +0 -11
  209. package/dist/src/plugin/recovery/storage.d.ts +0 -23
  210. package/dist/src/plugin/recovery/storage.js +0 -340
  211. package/dist/src/plugin/recovery/types.d.ts +0 -115
  212. package/dist/src/plugin/recovery/types.js +0 -6
  213. package/dist/src/plugin/recovery.d.ts +0 -60
  214. package/dist/src/plugin/recovery.js +0 -360
  215. package/dist/src/plugin/refresh-queue.d.ts +0 -99
  216. package/dist/src/plugin/refresh-queue.js +0 -235
  217. package/dist/src/plugin/request-helpers.d.ts +0 -281
  218. package/dist/src/plugin/request-helpers.js +0 -2200
  219. package/dist/src/plugin/request.d.ts +0 -110
  220. package/dist/src/plugin/request.js +0 -1489
  221. package/dist/src/plugin/rotation.d.ts +0 -182
  222. package/dist/src/plugin/rotation.js +0 -364
  223. package/dist/src/plugin/search.d.ts +0 -31
  224. package/dist/src/plugin/search.js +0 -185
  225. package/dist/src/plugin/server.d.ts +0 -22
  226. package/dist/src/plugin/server.js +0 -306
  227. package/dist/src/plugin/storage.d.ts +0 -136
  228. package/dist/src/plugin/storage.js +0 -599
  229. package/dist/src/plugin/stores/signature-store.d.ts +0 -4
  230. package/dist/src/plugin/stores/signature-store.js +0 -24
  231. package/dist/src/plugin/thinking-recovery.d.ts +0 -89
  232. package/dist/src/plugin/thinking-recovery.js +0 -289
  233. package/dist/src/plugin/token.d.ts +0 -18
  234. package/dist/src/plugin/token.js +0 -127
  235. package/dist/src/plugin/transform/claude.d.ts +0 -79
  236. package/dist/src/plugin/transform/claude.js +0 -256
  237. package/dist/src/plugin/transform/cross-model-sanitizer.d.ts +0 -34
  238. package/dist/src/plugin/transform/cross-model-sanitizer.js +0 -224
  239. package/dist/src/plugin/transform/gemini.d.ts +0 -132
  240. package/dist/src/plugin/transform/gemini.js +0 -659
  241. package/dist/src/plugin/transform/index.d.ts +0 -14
  242. package/dist/src/plugin/transform/index.js +0 -9
  243. package/dist/src/plugin/transform/model-resolver.d.ts +0 -98
  244. package/dist/src/plugin/transform/model-resolver.js +0 -320
  245. package/dist/src/plugin/transform/types.d.ts +0 -110
  246. package/dist/src/plugin/transform/types.js +0 -1
  247. package/dist/src/plugin/types.d.ts +0 -95
  248. package/dist/src/plugin/types.js +0 -1
  249. package/dist/src/plugin/ui/ansi.d.ts +0 -31
  250. package/dist/src/plugin/ui/ansi.js +0 -45
  251. package/dist/src/plugin/ui/auth-menu.d.ts +0 -47
  252. package/dist/src/plugin/ui/auth-menu.js +0 -199
  253. package/dist/src/plugin/ui/confirm.d.ts +0 -1
  254. package/dist/src/plugin/ui/confirm.js +0 -14
  255. package/dist/src/plugin/ui/select.d.ts +0 -22
  256. package/dist/src/plugin/ui/select.js +0 -243
  257. package/dist/src/plugin/version.d.ts +0 -18
  258. package/dist/src/plugin/version.js +0 -79
@@ -1,659 +0,0 @@
1
- /**
2
- * Gemini-specific Request Transformations
3
- *
4
- * Handles Gemini model-specific request transformations including:
5
- * - Thinking config (camelCase keys, thinkingLevel for Gemini 3)
6
- * - Tool normalization (function/custom format)
7
- * - Schema transformation (JSON Schema -> Gemini Schema format)
8
- */
9
- /**
10
- * Transform a JSON Schema to Gemini-compatible format.
11
- * Based on @google/genai SDK's processJsonSchema() function.
12
- *
13
- * Key transformations:
14
- * - Converts type values to uppercase (object -> OBJECT)
15
- * - Removes unsupported fields like additionalProperties, $schema
16
- * - Recursively processes nested schemas (properties, items, anyOf, etc.)
17
- *
18
- * @param schema - A JSON Schema object or primitive value
19
- * @returns Gemini-compatible schema
20
- *
21
- * Fields that Gemini API rejects and must be removed from schemas.
22
- * Antigravity uses strict protobuf-backed JSON validation.
23
- */
24
- const UNSUPPORTED_SCHEMA_FIELDS = new Set([
25
- "additionalProperties",
26
- "$schema",
27
- "$id",
28
- "$comment",
29
- "$ref",
30
- "$defs",
31
- "definitions",
32
- "const",
33
- "contentMediaType",
34
- "contentEncoding",
35
- "if",
36
- "then",
37
- "else",
38
- "not",
39
- "patternProperties",
40
- "unevaluatedProperties",
41
- "unevaluatedItems",
42
- "dependentRequired",
43
- "dependentSchemas",
44
- "propertyNames",
45
- "minContains",
46
- "maxContains",
47
- ]);
48
- export function toGeminiSchema(schema) {
49
- if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
50
- return schema;
51
- }
52
- const inputSchema = schema;
53
- const result = {};
54
- const propertyNames = new Set();
55
- if (inputSchema.properties && typeof inputSchema.properties === "object") {
56
- for (const propName of Object.keys(inputSchema.properties)) {
57
- propertyNames.add(propName);
58
- }
59
- }
60
- for (const [key, value] of Object.entries(inputSchema)) {
61
- if (UNSUPPORTED_SCHEMA_FIELDS.has(key)) {
62
- continue;
63
- }
64
- if (key === "type" && typeof value === "string") {
65
- result[key] = value.toUpperCase();
66
- }
67
- else if (key === "properties" && typeof value === "object" && value !== null) {
68
- const props = {};
69
- for (const [propName, propSchema] of Object.entries(value)) {
70
- props[propName] = toGeminiSchema(propSchema);
71
- }
72
- result[key] = props;
73
- }
74
- else if (key === "items" && typeof value === "object") {
75
- result[key] = toGeminiSchema(value);
76
- }
77
- else if ((key === "anyOf" || key === "oneOf" || key === "allOf") && Array.isArray(value)) {
78
- result[key] = value.map((item) => toGeminiSchema(item));
79
- }
80
- else if (key === "enum" && Array.isArray(value)) {
81
- result[key] = value;
82
- }
83
- else if (key === "default" || key === "examples") {
84
- result[key] = value;
85
- }
86
- else if (key === "required" && Array.isArray(value)) {
87
- if (propertyNames.size > 0) {
88
- const validRequired = value.filter((prop) => typeof prop === "string" && propertyNames.has(prop));
89
- if (validRequired.length > 0) {
90
- result[key] = validRequired;
91
- }
92
- }
93
- else {
94
- result[key] = value;
95
- }
96
- }
97
- else {
98
- result[key] = value;
99
- }
100
- }
101
- if (result.type === "ARRAY" && !result.items) {
102
- result.items = { type: "STRING" };
103
- }
104
- return result;
105
- }
106
- /**
107
- * Check if a model is a Gemini model (not Claude).
108
- */
109
- export function isGeminiModel(model) {
110
- const lower = model.toLowerCase();
111
- return lower.includes("gemini") && !lower.includes("claude");
112
- }
113
- /**
114
- * Check if a model is Gemini 3 (uses thinkingLevel string).
115
- */
116
- export function isGemini3Model(model) {
117
- return model.toLowerCase().includes("gemini-3");
118
- }
119
- /**
120
- * Check if a model is Gemini 2.5 (uses numeric thinkingBudget).
121
- */
122
- export function isGemini25Model(model) {
123
- return model.toLowerCase().includes("gemini-2.5");
124
- }
125
- /**
126
- * Check if a model is an image generation model.
127
- * Image models don't support thinking and require imageConfig.
128
- */
129
- export function isImageGenerationModel(model) {
130
- const lower = model.toLowerCase();
131
- return (lower.includes("image") ||
132
- lower.includes("imagen"));
133
- }
134
- /**
135
- * Build Gemini 3 thinking config with thinkingLevel string.
136
- */
137
- export function buildGemini3ThinkingConfig(includeThoughts, thinkingLevel) {
138
- return {
139
- includeThoughts,
140
- thinkingLevel,
141
- };
142
- }
143
- /**
144
- * Build Gemini 2.5 thinking config with numeric thinkingBudget.
145
- */
146
- export function buildGemini25ThinkingConfig(includeThoughts, thinkingBudget) {
147
- return {
148
- includeThoughts,
149
- ...(typeof thinkingBudget === "number" && thinkingBudget > 0 ? { thinkingBudget } : {}),
150
- };
151
- }
152
- /**
153
- * Valid aspect ratios for image generation.
154
- */
155
- const VALID_ASPECT_RATIOS = ["1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"];
156
- /**
157
- * Build image generation config for Gemini image models.
158
- *
159
- * Configuration is read from environment variables:
160
- * - OPENCODE_IMAGE_ASPECT_RATIO: Aspect ratio (e.g., "16:9", "4:3")
161
- *
162
- * Defaults to 1:1 aspect ratio if not specified.
163
- *
164
- * Note: Resolution setting is not currently supported by the Antigravity API.
165
- */
166
- export function buildImageGenerationConfig() {
167
- const aspectRatio = process.env.OPENCODE_IMAGE_ASPECT_RATIO || "1:1";
168
- if (VALID_ASPECT_RATIOS.includes(aspectRatio)) {
169
- return { aspectRatio };
170
- }
171
- console.warn(`[gemini] Invalid aspect ratio "${aspectRatio}". Using default "1:1". Valid values: ${VALID_ASPECT_RATIOS.join(", ")}`);
172
- return { aspectRatio: "1:1" };
173
- }
174
- /**
175
- * Normalize tools for Gemini models.
176
- * Ensures tools have proper function-style format.
177
- *
178
- * @returns Debug info about tool normalization
179
- */
180
- export function normalizeGeminiTools(payload) {
181
- let toolDebugMissing = 0;
182
- const toolDebugSummaries = [];
183
- if (!Array.isArray(payload.tools)) {
184
- return { toolDebugMissing, toolDebugSummaries };
185
- }
186
- payload.tools = payload.tools.map((tool, toolIndex) => {
187
- const t = tool;
188
- if (t.googleSearch || t.googleSearchRetrieval) {
189
- return t;
190
- }
191
- const newTool = { ...t };
192
- const schemaCandidates = [
193
- newTool.function?.input_schema,
194
- newTool.function?.parameters,
195
- newTool.function?.inputSchema,
196
- newTool.custom?.input_schema,
197
- newTool.custom?.parameters,
198
- newTool.parameters,
199
- newTool.input_schema,
200
- newTool.inputSchema,
201
- ].filter(Boolean);
202
- const placeholderSchema = {
203
- type: "OBJECT",
204
- properties: {
205
- _placeholder: {
206
- type: "BOOLEAN",
207
- description: "Placeholder. Always pass true.",
208
- },
209
- },
210
- required: ["_placeholder"],
211
- };
212
- let schema = schemaCandidates[0];
213
- const schemaObjectOk = schema && typeof schema === "object" && !Array.isArray(schema);
214
- if (!schemaObjectOk) {
215
- schema = placeholderSchema;
216
- toolDebugMissing += 1;
217
- }
218
- else {
219
- schema = toGeminiSchema(schema);
220
- }
221
- const nameCandidate = newTool.name ||
222
- newTool.function?.name ||
223
- newTool.custom?.name ||
224
- `tool-${toolIndex}`;
225
- // Always update function.input_schema with transformed schema
226
- if (newTool.function && schema) {
227
- newTool.function.input_schema = schema;
228
- }
229
- // Always update custom.input_schema with transformed schema
230
- if (newTool.custom && schema) {
231
- newTool.custom.input_schema = schema;
232
- }
233
- if (!newTool.custom && newTool.function) {
234
- const fn = newTool.function;
235
- newTool.custom = {
236
- name: fn.name || nameCandidate,
237
- description: fn.description,
238
- input_schema: schema,
239
- };
240
- }
241
- if (!newTool.custom && !newTool.function) {
242
- newTool.custom = {
243
- name: nameCandidate,
244
- description: newTool.description,
245
- input_schema: schema,
246
- };
247
- if (!newTool.parameters && !newTool.input_schema && !newTool.inputSchema) {
248
- newTool.parameters = schema;
249
- }
250
- }
251
- if (newTool.custom && !newTool.custom.input_schema) {
252
- newTool.custom.input_schema = {
253
- type: "OBJECT",
254
- properties: {},
255
- };
256
- toolDebugMissing += 1;
257
- }
258
- toolDebugSummaries.push(`idx=${toolIndex}, hasCustom=${!!newTool.custom}, customSchema=${!!newTool.custom?.input_schema}, hasFunction=${!!newTool.function}, functionSchema=${!!newTool.function?.input_schema}`);
259
- if (newTool.custom) {
260
- delete newTool.custom;
261
- }
262
- return newTool;
263
- });
264
- return { toolDebugMissing, toolDebugSummaries };
265
- }
266
- /**
267
- * Apply all Gemini-specific transformations.
268
- */
269
- export function applyGeminiTransforms(payload, options) {
270
- const { model, tierThinkingBudget, tierThinkingLevel, normalizedThinking, googleSearch } = options;
271
- // 1. Apply thinking config if needed
272
- if (normalizedThinking) {
273
- let thinkingConfig;
274
- if (tierThinkingLevel && isGemini3Model(model)) {
275
- thinkingConfig = buildGemini3ThinkingConfig(normalizedThinking.includeThoughts ?? true, tierThinkingLevel);
276
- }
277
- else {
278
- const thinkingBudget = tierThinkingBudget ?? normalizedThinking.thinkingBudget;
279
- thinkingConfig = buildGemini25ThinkingConfig(normalizedThinking.includeThoughts ?? true, thinkingBudget);
280
- }
281
- const generationConfig = (payload.generationConfig ?? {});
282
- generationConfig.thinkingConfig = thinkingConfig;
283
- payload.generationConfig = generationConfig;
284
- }
285
- // 2. Apply Google Search (Grounding) if enabled
286
- if (googleSearch && googleSearch.mode === 'auto') {
287
- const tools = payload.tools || [];
288
- if (!payload.tools) {
289
- payload.tools = tools;
290
- }
291
- payload.tools.push({
292
- googleSearch: {},
293
- });
294
- }
295
- // 3. Normalize tools
296
- const result = normalizeGeminiTools(payload);
297
- // 4. Wrap tools in functionDeclarations format (fixes #203, #206)
298
- // Must be: [{ functionDeclarations: [{ name, description, parameters }] }]
299
- const wrapResult = wrapToolsAsFunctionDeclarations(payload);
300
- return {
301
- ...result,
302
- wrappedFunctionCount: wrapResult.wrappedFunctionCount,
303
- passthroughToolCount: wrapResult.passthroughToolCount,
304
- };
305
- }
306
- /**
307
- * Wrap tools array in Gemini's required functionDeclarations format.
308
- *
309
- * Gemini/Antigravity API expects:
310
- * { tools: [{ functionDeclarations: [{ name, description, parameters }] }] }
311
- *
312
- * NOT:
313
- * { tools: [{ function: {...}, parameters: {...} }] }
314
- *
315
- * The wrapper-level 'parameters' field causes:
316
- * "Unknown name 'parameters' at 'request.tools[0]'"
317
- */
318
- /**
319
- * Detect if a tool is a web search tool in any of the supported formats:
320
- * - Claude/Anthropic: { type: "web_search_20250305" } or { name: "web_search" }
321
- * - Gemini native: { googleSearch: {} } or { googleSearchRetrieval: {} }
322
- */
323
- function isWebSearchTool(tool) {
324
- // 1. Gemini native format
325
- if (tool.googleSearch || tool.googleSearchRetrieval) {
326
- return true;
327
- }
328
- // 2. Claude/Anthropic format: { type: "web_search_20250305" }
329
- if (tool.type === "web_search_20250305") {
330
- return true;
331
- }
332
- // 3. Simple name-based format: { name: "web_search" | "google_search" }
333
- const name = tool.name;
334
- if (name === "web_search" || name === "google_search") {
335
- return true;
336
- }
337
- return false;
338
- }
339
- export function wrapToolsAsFunctionDeclarations(payload) {
340
- if (!Array.isArray(payload.tools) || payload.tools.length === 0) {
341
- return { wrappedFunctionCount: 0, passthroughToolCount: 0 };
342
- }
343
- const functionDeclarations = [];
344
- const passthroughTools = [];
345
- let hasWebSearchTool = false;
346
- for (const tool of payload.tools) {
347
- if (tool.googleSearch || tool.googleSearchRetrieval || tool.codeExecution) {
348
- passthroughTools.push(tool);
349
- continue;
350
- }
351
- if (isWebSearchTool(tool)) {
352
- hasWebSearchTool = true;
353
- continue; // Will be added as { googleSearch: {} } at the end
354
- }
355
- if (tool.functionDeclarations) {
356
- if (Array.isArray(tool.functionDeclarations)) {
357
- for (const decl of tool.functionDeclarations) {
358
- functionDeclarations.push({
359
- name: String(decl.name || `tool-${functionDeclarations.length}`),
360
- description: String(decl.description || ""),
361
- parameters: decl.parameters || { type: "OBJECT", properties: {} },
362
- });
363
- }
364
- }
365
- continue;
366
- }
367
- const fn = tool.function;
368
- const custom = tool.custom;
369
- const name = String(tool.name ||
370
- fn?.name ||
371
- custom?.name ||
372
- `tool-${functionDeclarations.length}`);
373
- const description = String(tool.description ||
374
- fn?.description ||
375
- custom?.description ||
376
- "");
377
- const schema = (fn?.input_schema ||
378
- fn?.parameters ||
379
- fn?.inputSchema ||
380
- custom?.input_schema ||
381
- custom?.parameters ||
382
- tool.parameters ||
383
- tool.input_schema ||
384
- tool.inputSchema ||
385
- { type: "OBJECT", properties: {} });
386
- functionDeclarations.push({
387
- name,
388
- description,
389
- parameters: schema,
390
- });
391
- }
392
- const finalTools = [];
393
- if (functionDeclarations.length > 0) {
394
- finalTools.push({ functionDeclarations });
395
- }
396
- finalTools.push(...passthroughTools);
397
- if (hasWebSearchTool && functionDeclarations.length === 0) {
398
- finalTools.push({ googleSearch: {} });
399
- }
400
- else if (hasWebSearchTool && functionDeclarations.length > 0) {
401
- console.warn("[gemini] web_search tool detected but cannot be combined with function declarations. " +
402
- "Use the explicit google_search() tool call instead.");
403
- }
404
- payload.tools = finalTools;
405
- return {
406
- wrappedFunctionCount: functionDeclarations.length,
407
- passthroughToolCount: passthroughTools.length + (hasWebSearchTool && functionDeclarations.length === 0 ? 1 : 0),
408
- };
409
- }
410
- /**
411
- * Separate parts into functionCall/functionResponse parts and other parts.
412
- */
413
- function separateParts(parts) {
414
- const functionCallParts = [];
415
- const functionResponseParts = [];
416
- const otherParts = [];
417
- for (const part of parts) {
418
- if (!part || typeof part !== "object") {
419
- otherParts.push(part);
420
- continue;
421
- }
422
- if (part.functionCall || part.function_call) {
423
- functionCallParts.push(part);
424
- }
425
- else if (part.functionResponse || part.function_response) {
426
- functionResponseParts.push(part);
427
- }
428
- else {
429
- otherParts.push(part);
430
- }
431
- }
432
- return { functionCallParts, functionResponseParts, otherParts };
433
- }
434
- /**
435
- * Some Gemini / Antigravity backends reject a single model turn that contains
436
- * multiple parallel functionCall parts, even when the following user turn has
437
- * matching functionResponses. Expand to strict call → response → call → response.
438
- */
439
- export function expandMultiFunctionCallModelTurns(contents) {
440
- if (!Array.isArray(contents) || contents.length === 0) {
441
- return contents;
442
- }
443
- const result = [];
444
- for (let i = 0; i < contents.length; i++) {
445
- const turn = contents[i];
446
- if (!turn || typeof turn !== "object" || turn.role !== "model" || !Array.isArray(turn.parts)) {
447
- result.push(turn);
448
- continue;
449
- }
450
- const fcParts = turn.parts.filter((p) => p && typeof p === "object" && (p.functionCall || p.function_call));
451
- if (fcParts.length <= 1) {
452
- result.push(turn);
453
- continue;
454
- }
455
- const next = contents[i + 1];
456
- if (!next || next.role !== "user" || !Array.isArray(next.parts)) {
457
- result.push(turn);
458
- continue;
459
- }
460
- const frParts = next.parts.filter((p) => p && typeof p === "object" && (p.functionResponse || p.function_response));
461
- if (frParts.length !== fcParts.length) {
462
- result.push(turn);
463
- continue;
464
- }
465
- const otherParts = turn.parts.filter((p) => !(p && typeof p === "object" && (p.functionCall || p.function_call)));
466
- for (let j = 0; j < fcParts.length; j++) {
467
- const modelParts = j === 0 && otherParts.length > 0 ? [...otherParts, fcParts[j]] : [fcParts[j]];
468
- result.push({ ...turn, role: "model", parts: modelParts });
469
- result.push({ role: "user", parts: [frParts[j]] });
470
- }
471
- i++;
472
- }
473
- return result;
474
- }
475
- /**
476
- * Sanitize Gemini conversation contents to enforce strict turn ordering.
477
- *
478
- * Gemini API rules:
479
- * 1. Strict user/model alternation (no consecutive same-role turns)
480
- * 2. functionCall parts must be in "model" role turns
481
- * 3. functionResponse parts must be in "user" role turns
482
- * 4. Conversation must start with "user"
483
- * 5. A function_call turn must come immediately after a user turn or
484
- * after a function_response turn
485
- *
486
- * This function:
487
- * - Normalizes roles ("assistant" to "model")
488
- * - Moves misplaced functionCall/functionResponse parts to correct roles
489
- * - Merges consecutive same-role turns
490
- * - Inserts empty filler turns to maintain alternation
491
- * - Ensures conversation starts with "user"
492
- */
493
- export function sanitizeGeminiContents(contents) {
494
- if (!Array.isArray(contents) || contents.length === 0) {
495
- return contents;
496
- }
497
- contents = expandMultiFunctionCallModelTurns(contents);
498
- const mergeTextParts = (parts) => {
499
- const merged = [];
500
- let currentText = "";
501
- for (const part of parts) {
502
- if (part && typeof part.text === "string") {
503
- currentText += (currentText ? "\n\n" : "") + part.text;
504
- }
505
- else {
506
- if (currentText) {
507
- merged.push({ text: currentText });
508
- currentText = "";
509
- }
510
- merged.push(part);
511
- }
512
- }
513
- if (currentText) {
514
- merged.push({ text: currentText });
515
- }
516
- return merged;
517
- };
518
- const normalized = [];
519
- for (const content of contents) {
520
- if (!content || typeof content !== "object")
521
- continue;
522
- let role = content.role;
523
- const parts = Array.isArray(content.parts) ? mergeTextParts([...content.parts]) : [];
524
- if (parts.length === 0)
525
- continue;
526
- if (role === "assistant") {
527
- role = "model";
528
- }
529
- const { functionCallParts, functionResponseParts, otherParts } = separateParts(parts);
530
- if (role === "model") {
531
- const modelParts = [...otherParts, ...functionCallParts];
532
- if (modelParts.length > 0) {
533
- normalized.push({ ...content, role: "model", parts: modelParts });
534
- }
535
- if (functionResponseParts.length > 0) {
536
- normalized.push({ role: "user", parts: functionResponseParts });
537
- }
538
- }
539
- else {
540
- if (functionCallParts.length > 0) {
541
- normalized.push({ role: "model", parts: functionCallParts });
542
- }
543
- if (functionResponseParts.length > 0) {
544
- normalized.push({ role: "user", parts: functionResponseParts });
545
- }
546
- if (otherParts.length > 0) {
547
- normalized.push({ ...content, role: "user", parts: otherParts });
548
- }
549
- }
550
- }
551
- if (normalized.length === 0) {
552
- return contents;
553
- }
554
- const merged = [normalized[0]];
555
- for (let i = 1; i < normalized.length; i++) {
556
- const current = normalized[i];
557
- const previous = merged[merged.length - 1];
558
- const hasFunc = (parts) => parts.some(p => p.functionCall || p.functionResponse || p.function_call || p.function_response);
559
- const prevFunc = hasFunc(previous.parts);
560
- const currFunc = hasFunc(current.parts);
561
- if (current.role === previous.role && prevFunc === currFunc) {
562
- previous.parts = [...previous.parts, ...current.parts];
563
- }
564
- else {
565
- merged.push(current);
566
- }
567
- }
568
- if (merged[0].role !== "user") {
569
- merged.unshift({ role: "user", parts: [{ text: "acknowledged" }] });
570
- }
571
- const result = [merged[0]];
572
- for (let i = 1; i < merged.length; i++) {
573
- const current = merged[i];
574
- const previous = result[result.length - 1];
575
- if (current.role === previous.role) {
576
- const fillerRole = current.role === "model" ? "user" : "model";
577
- result.push({ role: fillerRole, parts: [{ text: "acknowledged" }] });
578
- }
579
- result.push(current);
580
- }
581
- return result.map(turn => ({
582
- ...turn,
583
- parts: mergeTextParts(turn.parts)
584
- }));
585
- }
586
- /**
587
- * Fix Gemini tool call/response pairing.
588
- *
589
- * Ensures every functionCall in a model turn has a matching functionResponse
590
- * in the immediately following user turn. If not, injects a placeholder
591
- * response to prevent the API from rejecting the request.
592
- */
593
- export function fixGeminiToolPairing(contents) {
594
- if (!Array.isArray(contents) || contents.length === 0) {
595
- return contents;
596
- }
597
- const result = contents.map((c) => ({
598
- ...c,
599
- parts: Array.isArray(c.parts) ? [...c.parts] : [],
600
- }));
601
- const callsByModelIdx = new Map();
602
- for (let i = 0; i < result.length; i++) {
603
- const turn = result[i];
604
- if (turn.role !== "model")
605
- continue;
606
- const calls = [];
607
- for (const part of turn.parts) {
608
- const fc = part?.functionCall || part?.function_call;
609
- if (!fc)
610
- continue;
611
- calls.push({ name: fc.name || "unknown", id: fc.id || undefined });
612
- }
613
- if (calls.length > 0) {
614
- callsByModelIdx.set(i, calls);
615
- }
616
- }
617
- for (const [modelIdx, calls] of callsByModelIdx.entries()) {
618
- const nextIdx = modelIdx + 1;
619
- if (nextIdx >= result.length) {
620
- const responseParts = calls.map((call) => ({
621
- functionResponse: {
622
- name: call.name,
623
- ...(call.id ? { id: call.id } : {}),
624
- response: { result: "[pending]" },
625
- },
626
- }));
627
- result.push({ role: "user", parts: responseParts });
628
- continue;
629
- }
630
- const nextTurn = result[nextIdx];
631
- if (nextTurn.role !== "user")
632
- continue;
633
- const existingResponseNames = new Set();
634
- const existingResponseIds = new Set();
635
- for (const part of nextTurn.parts) {
636
- const fr = part?.functionResponse || part?.function_response;
637
- if (!fr)
638
- continue;
639
- if (fr.name)
640
- existingResponseNames.add(fr.name);
641
- if (fr.id)
642
- existingResponseIds.add(fr.id);
643
- }
644
- for (const call of calls) {
645
- const hasMatchById = call.id && existingResponseIds.has(call.id);
646
- const hasMatchByName = existingResponseNames.has(call.name);
647
- if (!hasMatchById && !hasMatchByName) {
648
- nextTurn.parts.push({
649
- functionResponse: {
650
- name: call.name,
651
- ...(call.id ? { id: call.id } : {}),
652
- response: { result: "[no response received]" },
653
- },
654
- });
655
- }
656
- }
657
- }
658
- return result;
659
- }
@@ -1,14 +0,0 @@
1
- /**
2
- * Transform Module Index
3
- *
4
- * Re-exports transform functions and types for request transformation.
5
- */
6
- export type { ModelFamily, ThinkingTier, TransformContext, TransformResult, TransformDebugInfo, RequestPayload, ThinkingConfig, ResolvedModel, GoogleSearchConfig, } from "./types";
7
- export { resolveModelWithTier, resolveModelWithVariant, resolveModelForHeaderStyle, getModelFamily, MODEL_ALIASES, THINKING_TIER_BUDGETS, GEMINI_3_THINKING_LEVELS, } from "./model-resolver";
8
- export type { VariantConfig } from "./model-resolver";
9
- export { isClaudeModel, isClaudeThinkingModel, configureClaudeToolConfig, buildClaudeThinkingConfig, ensureClaudeMaxOutputTokens, appendClaudeThinkingHint, normalizeClaudeTools, applyClaudeTransforms, CLAUDE_THINKING_MAX_OUTPUT_TOKENS, CLAUDE_INTERLEAVED_THINKING_HINT, } from "./claude";
10
- export type { ClaudeTransformOptions, ClaudeTransformResult } from "./claude";
11
- export { isGeminiModel, isGemini3Model, isGemini25Model, isImageGenerationModel, buildGemini3ThinkingConfig, buildGemini25ThinkingConfig, buildImageGenerationConfig, normalizeGeminiTools, applyGeminiTransforms, sanitizeGeminiContents, fixGeminiToolPairing, expandMultiFunctionCallModelTurns, } from "./gemini";
12
- export type { GeminiTransformOptions, GeminiTransformResult, ImageConfig } from "./gemini";
13
- export { sanitizeCrossModelPayload, sanitizeCrossModelPayloadInPlace, getModelFamily as getCrossModelFamily, stripGeminiThinkingMetadata, stripClaudeThinkingFields, } from "./cross-model-sanitizer";
14
- export type { SanitizerOptions } from "./cross-model-sanitizer";
@@ -1,9 +0,0 @@
1
- /**
2
- * Transform Module Index
3
- *
4
- * Re-exports transform functions and types for request transformation.
5
- */
6
- export { resolveModelWithTier, resolveModelWithVariant, resolveModelForHeaderStyle, getModelFamily, MODEL_ALIASES, THINKING_TIER_BUDGETS, GEMINI_3_THINKING_LEVELS, } from "./model-resolver";
7
- export { isClaudeModel, isClaudeThinkingModel, configureClaudeToolConfig, buildClaudeThinkingConfig, ensureClaudeMaxOutputTokens, appendClaudeThinkingHint, normalizeClaudeTools, applyClaudeTransforms, CLAUDE_THINKING_MAX_OUTPUT_TOKENS, CLAUDE_INTERLEAVED_THINKING_HINT, } from "./claude";
8
- export { isGeminiModel, isGemini3Model, isGemini25Model, isImageGenerationModel, buildGemini3ThinkingConfig, buildGemini25ThinkingConfig, buildImageGenerationConfig, normalizeGeminiTools, applyGeminiTransforms, sanitizeGeminiContents, fixGeminiToolPairing, expandMultiFunctionCallModelTurns, } from "./gemini";
9
- export { sanitizeCrossModelPayload, sanitizeCrossModelPayloadInPlace, getModelFamily as getCrossModelFamily, stripGeminiThinkingMetadata, stripClaudeThinkingFields, } from "./cross-model-sanitizer";