gsd-pi 2.16.0 → 2.18.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 (225) hide show
  1. package/README.md +39 -0
  2. package/dist/onboarding.js +2 -2
  3. package/dist/remote-questions-config.d.ts +10 -0
  4. package/dist/remote-questions-config.js +36 -0
  5. package/dist/resources/extensions/gsd/activity-log.ts +37 -7
  6. package/dist/resources/extensions/gsd/auto-dashboard.ts +4 -0
  7. package/dist/resources/extensions/gsd/auto-dispatch.ts +9 -3
  8. package/dist/resources/extensions/gsd/auto-prompts.ts +91 -42
  9. package/dist/resources/extensions/gsd/auto-recovery.ts +7 -2
  10. package/dist/resources/extensions/gsd/auto-worktree.ts +33 -4
  11. package/dist/resources/extensions/gsd/auto.ts +177 -25
  12. package/dist/resources/extensions/gsd/commands.ts +264 -23
  13. package/dist/resources/extensions/gsd/complexity.ts +236 -0
  14. package/dist/resources/extensions/gsd/dispatch-guard.ts +7 -19
  15. package/dist/resources/extensions/gsd/docs/preferences-reference.md +202 -2
  16. package/dist/resources/extensions/gsd/files.ts +129 -3
  17. package/dist/resources/extensions/gsd/git-service.ts +19 -8
  18. package/dist/resources/extensions/gsd/gitignore.ts +41 -2
  19. package/dist/resources/extensions/gsd/guided-flow.ts +247 -10
  20. package/dist/resources/extensions/gsd/index.ts +47 -3
  21. package/dist/resources/extensions/gsd/metrics.ts +44 -0
  22. package/dist/resources/extensions/gsd/native-git-bridge.ts +5 -0
  23. package/dist/resources/extensions/gsd/native-parser-bridge.ts +5 -0
  24. package/dist/resources/extensions/gsd/paths.ts +9 -0
  25. package/dist/resources/extensions/gsd/preferences.ts +181 -2
  26. package/dist/resources/extensions/gsd/prompts/execute-task.md +6 -5
  27. package/dist/resources/extensions/gsd/prompts/system.md +2 -0
  28. package/dist/resources/extensions/gsd/queue-order.ts +231 -0
  29. package/dist/resources/extensions/gsd/queue-reorder-ui.ts +263 -0
  30. package/dist/resources/extensions/gsd/routing-history.ts +290 -0
  31. package/dist/resources/extensions/gsd/state.ts +15 -3
  32. package/dist/resources/extensions/gsd/templates/knowledge.md +19 -0
  33. package/dist/resources/extensions/gsd/templates/preferences.md +14 -0
  34. package/dist/resources/extensions/gsd/tests/auto-recovery.test.ts +50 -0
  35. package/dist/resources/extensions/gsd/tests/auto-worktree.test.ts +20 -0
  36. package/dist/resources/extensions/gsd/tests/budget-prediction.test.ts +220 -0
  37. package/dist/resources/extensions/gsd/tests/complexity-routing.test.ts +294 -0
  38. package/dist/resources/extensions/gsd/tests/context-compression.test.ts +180 -0
  39. package/dist/resources/extensions/gsd/tests/derive-state-deps.test.ts +99 -0
  40. package/dist/resources/extensions/gsd/tests/git-service.test.ts +132 -0
  41. package/dist/resources/extensions/gsd/tests/in-flight-tool-tracking.test.ts +79 -0
  42. package/dist/resources/extensions/gsd/tests/knowledge.test.ts +161 -0
  43. package/dist/resources/extensions/gsd/tests/memory-leak-guards.test.ts +87 -0
  44. package/dist/resources/extensions/gsd/tests/preferences-git.test.ts +28 -0
  45. package/dist/resources/extensions/gsd/tests/preferences-wizard-fields.test.ts +168 -0
  46. package/dist/resources/extensions/gsd/tests/queue-order.test.ts +204 -0
  47. package/dist/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +281 -0
  48. package/dist/resources/extensions/gsd/tests/routing-history.test.ts +87 -0
  49. package/dist/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +139 -0
  50. package/dist/resources/extensions/gsd/tests/stop-auto-remote.test.ts +130 -0
  51. package/dist/resources/extensions/gsd/tests/token-profile.test.ts +263 -0
  52. package/dist/resources/extensions/gsd/types.ts +28 -0
  53. package/dist/resources/extensions/gsd/worktree-manager.ts +8 -5
  54. package/dist/resources/extensions/gsd/worktree.ts +24 -2
  55. package/dist/resources/extensions/shared/next-action-ui.ts +16 -1
  56. package/package.json +1 -1
  57. package/packages/pi-ai/dist/models.generated.d.ts +493 -13
  58. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  59. package/packages/pi-ai/dist/models.generated.js +422 -62
  60. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  61. package/packages/pi-ai/dist/providers/google-shared.d.ts +12 -0
  62. package/packages/pi-ai/dist/providers/google-shared.d.ts.map +1 -1
  63. package/packages/pi-ai/dist/providers/google-shared.js +9 -22
  64. package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
  65. package/packages/pi-ai/dist/providers/google-shared.test.d.ts +2 -0
  66. package/packages/pi-ai/dist/providers/google-shared.test.d.ts.map +1 -0
  67. package/packages/pi-ai/dist/providers/google-shared.test.js +125 -0
  68. package/packages/pi-ai/dist/providers/google-shared.test.js.map +1 -0
  69. package/packages/pi-ai/src/models.generated.ts +422 -62
  70. package/packages/pi-ai/src/providers/google-shared.test.ts +137 -0
  71. package/packages/pi-ai/src/providers/google-shared.ts +10 -19
  72. package/packages/pi-coding-agent/dist/cli/args.d.ts +5 -0
  73. package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
  74. package/packages/pi-coding-agent/dist/cli/args.js +21 -0
  75. package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
  76. package/packages/pi-coding-agent/dist/cli/list-models.d.ts +14 -3
  77. package/packages/pi-coding-agent/dist/cli/list-models.d.ts.map +1 -1
  78. package/packages/pi-coding-agent/dist/cli/list-models.js +52 -17
  79. package/packages/pi-coding-agent/dist/cli/list-models.js.map +1 -1
  80. package/packages/pi-coding-agent/dist/core/discovery-cache.d.ts +27 -0
  81. package/packages/pi-coding-agent/dist/core/discovery-cache.d.ts.map +1 -0
  82. package/packages/pi-coding-agent/dist/core/discovery-cache.js +79 -0
  83. package/packages/pi-coding-agent/dist/core/discovery-cache.js.map +1 -0
  84. package/packages/pi-coding-agent/dist/core/discovery-cache.test.d.ts +2 -0
  85. package/packages/pi-coding-agent/dist/core/discovery-cache.test.d.ts.map +1 -0
  86. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js +140 -0
  87. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js.map +1 -0
  88. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts +35 -0
  89. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts.map +1 -0
  90. package/packages/pi-coding-agent/dist/core/model-discovery.js +162 -0
  91. package/packages/pi-coding-agent/dist/core/model-discovery.js.map +1 -0
  92. package/packages/pi-coding-agent/dist/core/model-discovery.test.d.ts +2 -0
  93. package/packages/pi-coding-agent/dist/core/model-discovery.test.d.ts.map +1 -0
  94. package/packages/pi-coding-agent/dist/core/model-discovery.test.js +100 -0
  95. package/packages/pi-coding-agent/dist/core/model-discovery.test.js.map +1 -0
  96. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.d.ts +2 -0
  97. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.d.ts.map +1 -0
  98. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js +113 -0
  99. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js.map +1 -0
  100. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +26 -0
  101. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  102. package/packages/pi-coding-agent/dist/core/model-registry.js +98 -0
  103. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  104. package/packages/pi-coding-agent/dist/core/models-json-writer.d.ts +62 -0
  105. package/packages/pi-coding-agent/dist/core/models-json-writer.d.ts.map +1 -0
  106. package/packages/pi-coding-agent/dist/core/models-json-writer.js +145 -0
  107. package/packages/pi-coding-agent/dist/core/models-json-writer.js.map +1 -0
  108. package/packages/pi-coding-agent/dist/core/models-json-writer.test.d.ts +2 -0
  109. package/packages/pi-coding-agent/dist/core/models-json-writer.test.d.ts.map +1 -0
  110. package/packages/pi-coding-agent/dist/core/models-json-writer.test.js +118 -0
  111. package/packages/pi-coding-agent/dist/core/models-json-writer.test.js.map +1 -0
  112. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +9 -0
  113. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  114. package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
  115. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  116. package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
  117. package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
  118. package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
  119. package/packages/pi-coding-agent/dist/core/tools/edit-diff.d.ts +7 -7
  120. package/packages/pi-coding-agent/dist/core/tools/edit-diff.d.ts.map +1 -1
  121. package/packages/pi-coding-agent/dist/core/tools/edit-diff.js +209 -13
  122. package/packages/pi-coding-agent/dist/core/tools/edit-diff.js.map +1 -1
  123. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.d.ts +2 -0
  124. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.d.ts.map +1 -0
  125. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +67 -0
  126. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -0
  127. package/packages/pi-coding-agent/dist/index.d.ts +5 -1
  128. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  129. package/packages/pi-coding-agent/dist/index.js +4 -1
  130. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  131. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  132. package/packages/pi-coding-agent/dist/main.js +17 -2
  133. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  134. package/packages/pi-coding-agent/dist/modes/interactive/components/index.d.ts +1 -0
  135. package/packages/pi-coding-agent/dist/modes/interactive/components/index.d.ts.map +1 -1
  136. package/packages/pi-coding-agent/dist/modes/interactive/components/index.js +1 -0
  137. package/packages/pi-coding-agent/dist/modes/interactive/components/index.js.map +1 -1
  138. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +1 -1
  139. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
  140. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +25 -0
  141. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -0
  142. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +121 -0
  143. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -0
  144. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +1 -0
  145. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  146. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +32 -0
  147. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  148. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  149. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +10 -0
  150. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  151. package/packages/pi-coding-agent/src/cli/args.ts +21 -0
  152. package/packages/pi-coding-agent/src/cli/list-models.ts +70 -17
  153. package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +170 -0
  154. package/packages/pi-coding-agent/src/core/discovery-cache.ts +97 -0
  155. package/packages/pi-coding-agent/src/core/model-discovery.test.ts +125 -0
  156. package/packages/pi-coding-agent/src/core/model-discovery.ts +231 -0
  157. package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +135 -0
  158. package/packages/pi-coding-agent/src/core/model-registry.ts +107 -0
  159. package/packages/pi-coding-agent/src/core/models-json-writer.test.ts +145 -0
  160. package/packages/pi-coding-agent/src/core/models-json-writer.ts +188 -0
  161. package/packages/pi-coding-agent/src/core/settings-manager.ts +21 -0
  162. package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
  163. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +85 -0
  164. package/packages/pi-coding-agent/src/core/tools/edit-diff.ts +245 -17
  165. package/packages/pi-coding-agent/src/index.ts +5 -0
  166. package/packages/pi-coding-agent/src/main.ts +19 -2
  167. package/packages/pi-coding-agent/src/modes/interactive/components/index.ts +1 -0
  168. package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +1 -1
  169. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +163 -0
  170. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +37 -0
  171. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +13 -0
  172. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  173. package/pkg/dist/modes/interactive/theme/theme.js +10 -0
  174. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  175. package/src/resources/extensions/gsd/activity-log.ts +37 -7
  176. package/src/resources/extensions/gsd/auto-dashboard.ts +4 -0
  177. package/src/resources/extensions/gsd/auto-dispatch.ts +9 -3
  178. package/src/resources/extensions/gsd/auto-prompts.ts +91 -42
  179. package/src/resources/extensions/gsd/auto-recovery.ts +7 -2
  180. package/src/resources/extensions/gsd/auto-worktree.ts +33 -4
  181. package/src/resources/extensions/gsd/auto.ts +177 -25
  182. package/src/resources/extensions/gsd/commands.ts +264 -23
  183. package/src/resources/extensions/gsd/complexity.ts +236 -0
  184. package/src/resources/extensions/gsd/dispatch-guard.ts +7 -19
  185. package/src/resources/extensions/gsd/docs/preferences-reference.md +202 -2
  186. package/src/resources/extensions/gsd/files.ts +129 -3
  187. package/src/resources/extensions/gsd/git-service.ts +19 -8
  188. package/src/resources/extensions/gsd/gitignore.ts +41 -2
  189. package/src/resources/extensions/gsd/guided-flow.ts +247 -10
  190. package/src/resources/extensions/gsd/index.ts +47 -3
  191. package/src/resources/extensions/gsd/metrics.ts +44 -0
  192. package/src/resources/extensions/gsd/native-git-bridge.ts +5 -0
  193. package/src/resources/extensions/gsd/native-parser-bridge.ts +5 -0
  194. package/src/resources/extensions/gsd/paths.ts +9 -0
  195. package/src/resources/extensions/gsd/preferences.ts +181 -2
  196. package/src/resources/extensions/gsd/prompts/execute-task.md +6 -5
  197. package/src/resources/extensions/gsd/prompts/system.md +2 -0
  198. package/src/resources/extensions/gsd/queue-order.ts +231 -0
  199. package/src/resources/extensions/gsd/queue-reorder-ui.ts +263 -0
  200. package/src/resources/extensions/gsd/routing-history.ts +290 -0
  201. package/src/resources/extensions/gsd/state.ts +15 -3
  202. package/src/resources/extensions/gsd/templates/knowledge.md +19 -0
  203. package/src/resources/extensions/gsd/templates/preferences.md +14 -0
  204. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +50 -0
  205. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +20 -0
  206. package/src/resources/extensions/gsd/tests/budget-prediction.test.ts +220 -0
  207. package/src/resources/extensions/gsd/tests/complexity-routing.test.ts +294 -0
  208. package/src/resources/extensions/gsd/tests/context-compression.test.ts +180 -0
  209. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +99 -0
  210. package/src/resources/extensions/gsd/tests/git-service.test.ts +132 -0
  211. package/src/resources/extensions/gsd/tests/in-flight-tool-tracking.test.ts +79 -0
  212. package/src/resources/extensions/gsd/tests/knowledge.test.ts +161 -0
  213. package/src/resources/extensions/gsd/tests/memory-leak-guards.test.ts +87 -0
  214. package/src/resources/extensions/gsd/tests/preferences-git.test.ts +28 -0
  215. package/src/resources/extensions/gsd/tests/preferences-wizard-fields.test.ts +168 -0
  216. package/src/resources/extensions/gsd/tests/queue-order.test.ts +204 -0
  217. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +281 -0
  218. package/src/resources/extensions/gsd/tests/routing-history.test.ts +87 -0
  219. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +139 -0
  220. package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +130 -0
  221. package/src/resources/extensions/gsd/tests/token-profile.test.ts +263 -0
  222. package/src/resources/extensions/gsd/types.ts +28 -0
  223. package/src/resources/extensions/gsd/worktree-manager.ts +8 -5
  224. package/src/resources/extensions/gsd/worktree.ts +24 -2
  225. package/src/resources/extensions/shared/next-action-ui.ts +16 -1
@@ -38,6 +38,18 @@ export declare function requiresToolCallId(modelId: string): boolean;
38
38
  * Convert internal messages to Gemini Content[] format.
39
39
  */
40
40
  export declare function convertMessages<T extends GoogleApiType>(model: Model<T>, context: Context): Content[];
41
+ /**
42
+ * Sanitize a JSON Schema for Google's function declarations API.
43
+ * Google's API rejects `patternProperties` and `const` fields which are valid in JSON Schema.
44
+ *
45
+ * This function recursively:
46
+ * - Removes all `patternProperties` fields
47
+ * - Converts `const: "value"` to `enum: ["value"]` in anyOf/oneOf blocks
48
+ *
49
+ * This is needed for providers like `google-antigravity` when proxying Claude models,
50
+ * since Google Cloud Code Assist uses a restricted subset of JSON Schema.
51
+ */
52
+ export declare function sanitizeSchemaForGoogle(schema: unknown): unknown;
41
53
  /**
42
54
  * Convert tools to Gemini function declarations format.
43
55
  *
@@ -1 +1 @@
1
- {"version":3,"file":"google-shared.d.ts","sourceRoot":"","sources":["../../src/providers/google-shared.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,OAAO,EAAE,YAAY,EAAE,yBAAyB,EAAE,KAAK,IAAI,EAAE,MAAM,eAAe,CAAC;AACjG,OAAO,KAAK,EAAE,OAAO,EAAgB,KAAK,EAAE,UAAU,EAAe,IAAI,EAAE,MAAM,aAAa,CAAC;AAI/F,KAAK,aAAa,GAAG,sBAAsB,GAAG,mBAAmB,GAAG,eAAe,CAAC;AAEpF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,GAAG,kBAAkB,CAAC,GAAG,OAAO,CAExF;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAGrH;AAuBD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,aAAa,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,CAuJrG;AA0DD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC3B,KAAK,EAAE,IAAI,EAAE,EACb,aAAa,UAAQ,GACnB;IAAE,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;CAAE,EAAE,GAAG,SAAS,CAanE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,yBAAyB,CAWvE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,UAAU,CA0B9D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAS9D"}
1
+ {"version":3,"file":"google-shared.d.ts","sourceRoot":"","sources":["../../src/providers/google-shared.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,OAAO,EAAE,YAAY,EAAE,yBAAyB,EAAE,KAAK,IAAI,EAAE,MAAM,eAAe,CAAC;AACjG,OAAO,KAAK,EAAE,OAAO,EAAgB,KAAK,EAAE,UAAU,EAAe,IAAI,EAAE,MAAM,aAAa,CAAC;AAI/F,KAAK,aAAa,GAAG,sBAAsB,GAAG,mBAAmB,GAAG,eAAe,CAAC;AAEpF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,GAAG,kBAAkB,CAAC,GAAG,OAAO,CAExF;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAGrH;AAuBD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,aAAa,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,CAuJrG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAiChE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC3B,KAAK,EAAE,IAAI,EAAE,EACb,aAAa,UAAQ,GACnB;IAAE,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;CAAE,EAAE,GAAG,SAAS,CAanE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,yBAAyB,CAWvE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,UAAU,CA2B9D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAS9D"}
@@ -228,7 +228,7 @@ export function convertMessages(model, context) {
228
228
  * This is needed for providers like `google-antigravity` when proxying Claude models,
229
229
  * since Google Cloud Code Assist uses a restricted subset of JSON Schema.
230
230
  */
231
- function sanitizeSchemaForGoogle(schema) {
231
+ export function sanitizeSchemaForGoogle(schema) {
232
232
  if (!schema || typeof schema !== "object") {
233
233
  return schema;
234
234
  }
@@ -238,31 +238,17 @@ function sanitizeSchemaForGoogle(schema) {
238
238
  const obj = schema;
239
239
  const sanitized = {};
240
240
  for (const [key, value] of Object.entries(obj)) {
241
- // Skip patternProperties entirely
241
+ // Skip patternProperties entirely — not supported by Google's API
242
242
  if (key === "patternProperties") {
243
243
  continue;
244
244
  }
245
- // Convert const to enum in anyOf/oneOf blocks
245
+ // Convert const to enum Google's API rejects the const keyword
246
246
  if (key === "const" && typeof value === "string") {
247
- // Only convert if we're inside anyOf/oneOf; otherwise leave as-is
248
- // This will be handled by the anyOf/oneOf case below
249
247
  sanitized.enum = [value];
250
248
  continue;
251
249
  }
252
- // Recursively sanitize nested objects and arrays
253
- if (key === "properties" && typeof value === "object") {
254
- sanitized[key] = sanitizeSchemaForGoogle(value);
255
- }
256
- else if (key === "items" && typeof value === "object") {
257
- sanitized[key] = sanitizeSchemaForGoogle(value);
258
- }
259
- else if (key === "anyOf" || key === "oneOf" || key === "allOf") {
260
- sanitized[key] = sanitizeSchemaForGoogle(value);
261
- }
262
- else if (key === "additionalProperties" && typeof value === "object") {
263
- sanitized[key] = sanitizeSchemaForGoogle(value);
264
- }
265
- else if (typeof value === "object" && !Array.isArray(value)) {
250
+ // Recursively sanitize all nested objects and arrays
251
+ if (typeof value === "object") {
266
252
  sanitized[key] = sanitizeSchemaForGoogle(value);
267
253
  }
268
254
  else {
@@ -337,9 +323,10 @@ export function mapStopReason(reason) {
337
323
  case FinishReason.UNEXPECTED_TOOL_CALL:
338
324
  case FinishReason.NO_IMAGE:
339
325
  return "error";
340
- default:
341
- // Fallback for new/unknown FinishReason values
342
- return "error";
326
+ default: {
327
+ const _exhaustive = reason;
328
+ throw new Error(`Unhandled stop reason: ${_exhaustive}`);
329
+ }
343
330
  }
344
331
  }
345
332
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"google-shared.js","sourceRoot":"","sources":["../../src/providers/google-shared.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared utilities for Google Generative AI and Google Cloud Code Assist providers.\n */\n\nimport { type Content, FinishReason, FunctionCallingConfigMode, type Part } from \"@google/genai\";\nimport type { Context, ImageContent, Model, StopReason, TextContent, Tool } from \"../types.js\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.js\";\nimport { transformMessages } from \"./transform-messages.js\";\n\ntype GoogleApiType = \"google-generative-ai\" | \"google-gemini-cli\" | \"google-vertex\";\n\n/**\n * Determines whether a streamed Gemini `Part` should be treated as \"thinking\".\n *\n * Protocol note (Gemini / Vertex AI thought signatures):\n * - `thought: true` is the definitive marker for thinking content (thought summaries).\n * - `thoughtSignature` is an encrypted representation of the model's internal thought process\n * used to preserve reasoning context across multi-turn interactions.\n * - `thoughtSignature` can appear on ANY part type (text, functionCall, etc.) - it does NOT\n * indicate the part itself is thinking content.\n * - For non-functionCall responses, the signature appears on the last part for context replay.\n * - When persisting/replaying model outputs, signature-bearing parts must be preserved as-is;\n * do not merge/move signatures across parts.\n *\n * See: https://ai.google.dev/gemini-api/docs/thought-signatures\n */\nexport function isThinkingPart(part: Pick<Part, \"thought\" | \"thoughtSignature\">): boolean {\n\treturn part.thought === true;\n}\n\n/**\n * Retain thought signatures during streaming.\n *\n * Some backends only send `thoughtSignature` on the first delta for a given part/block; later deltas may omit it.\n * This helper preserves the last non-empty signature for the current block.\n *\n * Note: this does NOT merge or move signatures across distinct response parts. It only prevents\n * a signature from being overwritten with `undefined` within the same streamed block.\n */\nexport function retainThoughtSignature(existing: string | undefined, incoming: string | undefined): string | undefined {\n\tif (typeof incoming === \"string\" && incoming.length > 0) return incoming;\n\treturn existing;\n}\n\n// Thought signatures must be base64 for Google APIs (TYPE_BYTES).\nconst base64SignaturePattern = /^[A-Za-z0-9+/]+={0,2}$/;\n\n// Sentinel value that tells the Gemini API to skip thought signature validation.\n// Used for unsigned function call parts (e.g. replayed from providers without thought signatures).\n// See: https://ai.google.dev/gemini-api/docs/thought-signatures\nconst SKIP_THOUGHT_SIGNATURE = \"skip_thought_signature_validator\";\n\nfunction isValidThoughtSignature(signature: string | undefined): boolean {\n\tif (!signature) return false;\n\tif (signature.length % 4 !== 0) return false;\n\treturn base64SignaturePattern.test(signature);\n}\n\n/**\n * Only keep signatures from the same provider/model and with valid base64.\n */\nfunction resolveThoughtSignature(isSameProviderAndModel: boolean, signature: string | undefined): string | undefined {\n\treturn isSameProviderAndModel && isValidThoughtSignature(signature) ? signature : undefined;\n}\n\n/**\n * Models via Google APIs that require explicit tool call IDs in function calls/responses.\n */\nexport function requiresToolCallId(modelId: string): boolean {\n\treturn modelId.startsWith(\"claude-\") || modelId.startsWith(\"gpt-oss-\");\n}\n\n/**\n * Convert internal messages to Gemini Content[] format.\n */\nexport function convertMessages<T extends GoogleApiType>(model: Model<T>, context: Context): Content[] {\n\tconst contents: Content[] = [];\n\tconst normalizeToolCallId = (id: string): string => {\n\t\tif (!requiresToolCallId(model.id)) return id;\n\t\treturn id.replace(/[^a-zA-Z0-9_-]/g, \"_\").slice(0, 64);\n\t};\n\n\tconst transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);\n\n\tfor (const msg of transformedMessages) {\n\t\tif (msg.role === \"user\") {\n\t\t\tif (typeof msg.content === \"string\") {\n\t\t\t\tcontents.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tparts: [{ text: sanitizeSurrogates(msg.content) }],\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst parts: Part[] = msg.content.map((item) => {\n\t\t\t\t\tif (item.type === \"text\") {\n\t\t\t\t\t\treturn { text: sanitizeSurrogates(item.text) };\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tinlineData: {\n\t\t\t\t\t\t\t\tmimeType: item.mimeType,\n\t\t\t\t\t\t\t\tdata: item.data,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tconst filteredParts = !model.input.includes(\"image\") ? parts.filter((p) => p.text !== undefined) : parts;\n\t\t\t\tif (filteredParts.length === 0) continue;\n\t\t\t\tcontents.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tparts: filteredParts,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (msg.role === \"assistant\") {\n\t\t\tconst parts: Part[] = [];\n\t\t\t// Check if message is from same provider and model - only then keep thinking blocks\n\t\t\tconst isSameProviderAndModel = msg.provider === model.provider && msg.model === model.id;\n\n\t\t\tfor (const block of msg.content) {\n\t\t\t\tif (block.type === \"text\") {\n\t\t\t\t\t// Skip empty text blocks - they can cause issues with some models (e.g. Claude via Antigravity)\n\t\t\t\t\tif (!block.text || block.text.trim() === \"\") continue;\n\t\t\t\t\tconst thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.textSignature);\n\t\t\t\t\tparts.push({\n\t\t\t\t\t\ttext: sanitizeSurrogates(block.text),\n\t\t\t\t\t\t...(thoughtSignature && { thoughtSignature }),\n\t\t\t\t\t});\n\t\t\t\t} else if (block.type === \"thinking\") {\n\t\t\t\t\t// Skip empty thinking blocks\n\t\t\t\t\tif (!block.thinking || block.thinking.trim() === \"\") continue;\n\t\t\t\t\t// Only keep as thinking block if same provider AND same model\n\t\t\t\t\t// Otherwise convert to plain text (no tags to avoid model mimicking them)\n\t\t\t\t\tif (isSameProviderAndModel) {\n\t\t\t\t\t\tconst thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.thinkingSignature);\n\t\t\t\t\t\tparts.push({\n\t\t\t\t\t\t\tthought: true,\n\t\t\t\t\t\t\ttext: sanitizeSurrogates(block.thinking),\n\t\t\t\t\t\t\t...(thoughtSignature && { thoughtSignature }),\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tparts.push({\n\t\t\t\t\t\t\ttext: sanitizeSurrogates(block.thinking),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\tconst thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.thoughtSignature);\n\t\t\t\t\t// Gemini 3 requires thoughtSignature on all function calls when thinking mode is enabled.\n\t\t\t\t\t// Use the skip_thought_signature_validator sentinel for unsigned function calls\n\t\t\t\t\t// (e.g. replayed from providers without thought signatures like Claude via Antigravity).\n\t\t\t\t\tconst isGemini3 = model.id.toLowerCase().includes(\"gemini-3\");\n\t\t\t\t\tconst effectiveSignature = thoughtSignature || (isGemini3 ? SKIP_THOUGHT_SIGNATURE : undefined);\n\t\t\t\t\tconst part: Part = {\n\t\t\t\t\t\tfunctionCall: {\n\t\t\t\t\t\t\tname: block.name,\n\t\t\t\t\t\t\targs: block.arguments ?? {},\n\t\t\t\t\t\t\t...(requiresToolCallId(model.id) ? { id: block.id } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...(effectiveSignature && { thoughtSignature: effectiveSignature }),\n\t\t\t\t\t};\n\t\t\t\t\tparts.push(part);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (parts.length === 0) continue;\n\t\t\tcontents.push({\n\t\t\t\trole: \"model\",\n\t\t\t\tparts,\n\t\t\t});\n\t\t} else if (msg.role === \"toolResult\") {\n\t\t\t// Extract text and image content\n\t\t\tconst textContent = msg.content.filter((c): c is TextContent => c.type === \"text\");\n\t\t\tconst textResult = textContent.map((c) => c.text).join(\"\\n\");\n\t\t\tconst imageContent = model.input.includes(\"image\")\n\t\t\t\t? msg.content.filter((c): c is ImageContent => c.type === \"image\")\n\t\t\t\t: [];\n\n\t\t\tconst hasText = textResult.length > 0;\n\t\t\tconst hasImages = imageContent.length > 0;\n\n\t\t\t// Gemini 3 supports multimodal function responses with images nested inside functionResponse.parts\n\t\t\t// See: https://ai.google.dev/gemini-api/docs/function-calling#multimodal\n\t\t\t// Older models don't support this, so we put images in a separate user message.\n\t\t\tconst supportsMultimodalFunctionResponse = model.id.includes(\"gemini-3\");\n\n\t\t\t// Use \"output\" key for success, \"error\" key for errors as per SDK documentation\n\t\t\tconst responseValue = hasText ? sanitizeSurrogates(textResult) : hasImages ? \"(see attached image)\" : \"\";\n\n\t\t\tconst imageParts: Part[] = imageContent.map((imageBlock) => ({\n\t\t\t\tinlineData: {\n\t\t\t\t\tmimeType: imageBlock.mimeType,\n\t\t\t\t\tdata: imageBlock.data,\n\t\t\t\t},\n\t\t\t}));\n\n\t\t\tconst includeId = requiresToolCallId(model.id);\n\t\t\tconst functionResponsePart: Part = {\n\t\t\t\tfunctionResponse: {\n\t\t\t\t\tname: msg.toolName,\n\t\t\t\t\tresponse: msg.isError ? { error: responseValue } : { output: responseValue },\n\t\t\t\t\t// Nest images inside functionResponse.parts for Gemini 3\n\t\t\t\t\t...(hasImages && supportsMultimodalFunctionResponse && { parts: imageParts }),\n\t\t\t\t\t...(includeId ? { id: msg.toolCallId } : {}),\n\t\t\t\t},\n\t\t\t};\n\n\t\t\t// Cloud Code Assist API requires all function responses to be in a single user turn.\n\t\t\t// Check if the last content is already a user turn with function responses and merge.\n\t\t\tconst lastContent = contents[contents.length - 1];\n\t\t\tif (lastContent?.role === \"user\" && lastContent.parts?.some((p: Part) => p.functionResponse)) {\n\t\t\t\tlastContent.parts.push(functionResponsePart);\n\t\t\t} else {\n\t\t\t\tcontents.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tparts: [functionResponsePart],\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// For older models, add images in a separate user message\n\t\t\tif (hasImages && !supportsMultimodalFunctionResponse) {\n\t\t\t\tcontents.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tparts: [{ text: \"Tool result image:\" }, ...imageParts],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn contents;\n}\n\n/**\n * Sanitize a JSON Schema for Google's function declarations API.\n * Google's API rejects `patternProperties` and `const` fields which are valid in JSON Schema.\n *\n * This function recursively:\n * - Removes all `patternProperties` fields\n * - Converts `const: \"value\"` to `enum: [\"value\"]` in anyOf/oneOf blocks\n *\n * This is needed for providers like `google-antigravity` when proxying Claude models,\n * since Google Cloud Code Assist uses a restricted subset of JSON Schema.\n */\nfunction sanitizeSchemaForGoogle(schema: unknown): unknown {\n\tif (!schema || typeof schema !== \"object\") {\n\t\treturn schema;\n\t}\n\n\tif (Array.isArray(schema)) {\n\t\treturn schema.map((item) => sanitizeSchemaForGoogle(item));\n\t}\n\n\tconst obj = schema as Record<string, unknown>;\n\tconst sanitized: Record<string, unknown> = {};\n\n\tfor (const [key, value] of Object.entries(obj)) {\n\t\t// Skip patternProperties entirely\n\t\tif (key === \"patternProperties\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Convert const to enum in anyOf/oneOf blocks\n\t\tif (key === \"const\" && typeof value === \"string\") {\n\t\t\t// Only convert if we're inside anyOf/oneOf; otherwise leave as-is\n\t\t\t// This will be handled by the anyOf/oneOf case below\n\t\t\tsanitized.enum = [value];\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Recursively sanitize nested objects and arrays\n\t\tif (key === \"properties\" && typeof value === \"object\") {\n\t\t\tsanitized[key] = sanitizeSchemaForGoogle(value);\n\t\t} else if (key === \"items\" && typeof value === \"object\") {\n\t\t\tsanitized[key] = sanitizeSchemaForGoogle(value);\n\t\t} else if (key === \"anyOf\" || key === \"oneOf\" || key === \"allOf\") {\n\t\t\tsanitized[key] = sanitizeSchemaForGoogle(value);\n\t\t} else if (key === \"additionalProperties\" && typeof value === \"object\") {\n\t\t\tsanitized[key] = sanitizeSchemaForGoogle(value);\n\t\t} else if (typeof value === \"object\" && !Array.isArray(value)) {\n\t\t\tsanitized[key] = sanitizeSchemaForGoogle(value);\n\t\t} else {\n\t\t\tsanitized[key] = value;\n\t\t}\n\t}\n\n\treturn sanitized;\n}\n\n/**\n * Convert tools to Gemini function declarations format.\n *\n * By default uses `parametersJsonSchema` which supports full JSON Schema (including\n * anyOf, oneOf, const, etc.). Set `useParameters` to true to use the legacy `parameters`\n * field instead (OpenAPI 3.03 Schema). This is needed for Cloud Code Assist with Claude\n * models, where the API translates `parameters` into Anthropic's `input_schema`.\n *\n * The schema is automatically sanitized to remove fields not supported by Google's\n * function declarations API (patternProperties, const converted to enum, etc.).\n */\nexport function convertTools(\n\ttools: Tool[],\n\tuseParameters = false,\n): { functionDeclarations: Record<string, unknown>[] }[] | undefined {\n\tif (tools.length === 0) return undefined;\n\treturn [\n\t\t{\n\t\t\tfunctionDeclarations: tools.map((tool) => ({\n\t\t\t\tname: tool.name,\n\t\t\t\tdescription: tool.description,\n\t\t\t\t...(useParameters\n\t\t\t\t\t? { parameters: sanitizeSchemaForGoogle(tool.parameters) }\n\t\t\t\t\t: { parametersJsonSchema: sanitizeSchemaForGoogle(tool.parameters) }),\n\t\t\t})),\n\t\t},\n\t];\n}\n\n/**\n * Map tool choice string to Gemini FunctionCallingConfigMode.\n */\nexport function mapToolChoice(choice: string): FunctionCallingConfigMode {\n\tswitch (choice) {\n\t\tcase \"auto\":\n\t\t\treturn FunctionCallingConfigMode.AUTO;\n\t\tcase \"none\":\n\t\t\treturn FunctionCallingConfigMode.NONE;\n\t\tcase \"any\":\n\t\t\treturn FunctionCallingConfigMode.ANY;\n\t\tdefault:\n\t\t\treturn FunctionCallingConfigMode.AUTO;\n\t}\n}\n\n/**\n * Map Gemini FinishReason to our StopReason.\n */\nexport function mapStopReason(reason: FinishReason): StopReason {\n\tswitch (reason) {\n\t\tcase FinishReason.STOP:\n\t\t\treturn \"stop\";\n\t\tcase FinishReason.MAX_TOKENS:\n\t\t\treturn \"length\";\n\t\tcase FinishReason.BLOCKLIST:\n\t\tcase FinishReason.PROHIBITED_CONTENT:\n\t\tcase FinishReason.SPII:\n\t\tcase FinishReason.SAFETY:\n\t\tcase FinishReason.IMAGE_SAFETY:\n\t\tcase FinishReason.IMAGE_PROHIBITED_CONTENT:\n\t\tcase FinishReason.IMAGE_RECITATION:\n\t\tcase FinishReason.IMAGE_OTHER:\n\t\tcase FinishReason.RECITATION:\n\t\tcase FinishReason.FINISH_REASON_UNSPECIFIED:\n\t\tcase FinishReason.OTHER:\n\t\tcase FinishReason.LANGUAGE:\n\t\tcase FinishReason.MALFORMED_FUNCTION_CALL:\n\t\tcase FinishReason.UNEXPECTED_TOOL_CALL:\n\t\tcase FinishReason.NO_IMAGE:\n\t\t\treturn \"error\";\n\t\tdefault:\n\t\t\t// Fallback for new/unknown FinishReason values\n\t\t\treturn \"error\";\n\t}\n}\n\n/**\n * Map string finish reason to our StopReason (for raw API responses).\n */\nexport function mapStopReasonString(reason: string): StopReason {\n\tswitch (reason) {\n\t\tcase \"STOP\":\n\t\t\treturn \"stop\";\n\t\tcase \"MAX_TOKENS\":\n\t\t\treturn \"length\";\n\t\tdefault:\n\t\t\treturn \"error\";\n\t}\n}\n"]}
1
+ {"version":3,"file":"google-shared.js","sourceRoot":"","sources":["../../src/providers/google-shared.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared utilities for Google Generative AI and Google Cloud Code Assist providers.\n */\n\nimport { type Content, FinishReason, FunctionCallingConfigMode, type Part } from \"@google/genai\";\nimport type { Context, ImageContent, Model, StopReason, TextContent, Tool } from \"../types.js\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.js\";\nimport { transformMessages } from \"./transform-messages.js\";\n\ntype GoogleApiType = \"google-generative-ai\" | \"google-gemini-cli\" | \"google-vertex\";\n\n/**\n * Determines whether a streamed Gemini `Part` should be treated as \"thinking\".\n *\n * Protocol note (Gemini / Vertex AI thought signatures):\n * - `thought: true` is the definitive marker for thinking content (thought summaries).\n * - `thoughtSignature` is an encrypted representation of the model's internal thought process\n * used to preserve reasoning context across multi-turn interactions.\n * - `thoughtSignature` can appear on ANY part type (text, functionCall, etc.) - it does NOT\n * indicate the part itself is thinking content.\n * - For non-functionCall responses, the signature appears on the last part for context replay.\n * - When persisting/replaying model outputs, signature-bearing parts must be preserved as-is;\n * do not merge/move signatures across parts.\n *\n * See: https://ai.google.dev/gemini-api/docs/thought-signatures\n */\nexport function isThinkingPart(part: Pick<Part, \"thought\" | \"thoughtSignature\">): boolean {\n\treturn part.thought === true;\n}\n\n/**\n * Retain thought signatures during streaming.\n *\n * Some backends only send `thoughtSignature` on the first delta for a given part/block; later deltas may omit it.\n * This helper preserves the last non-empty signature for the current block.\n *\n * Note: this does NOT merge or move signatures across distinct response parts. It only prevents\n * a signature from being overwritten with `undefined` within the same streamed block.\n */\nexport function retainThoughtSignature(existing: string | undefined, incoming: string | undefined): string | undefined {\n\tif (typeof incoming === \"string\" && incoming.length > 0) return incoming;\n\treturn existing;\n}\n\n// Thought signatures must be base64 for Google APIs (TYPE_BYTES).\nconst base64SignaturePattern = /^[A-Za-z0-9+/]+={0,2}$/;\n\n// Sentinel value that tells the Gemini API to skip thought signature validation.\n// Used for unsigned function call parts (e.g. replayed from providers without thought signatures).\n// See: https://ai.google.dev/gemini-api/docs/thought-signatures\nconst SKIP_THOUGHT_SIGNATURE = \"skip_thought_signature_validator\";\n\nfunction isValidThoughtSignature(signature: string | undefined): boolean {\n\tif (!signature) return false;\n\tif (signature.length % 4 !== 0) return false;\n\treturn base64SignaturePattern.test(signature);\n}\n\n/**\n * Only keep signatures from the same provider/model and with valid base64.\n */\nfunction resolveThoughtSignature(isSameProviderAndModel: boolean, signature: string | undefined): string | undefined {\n\treturn isSameProviderAndModel && isValidThoughtSignature(signature) ? signature : undefined;\n}\n\n/**\n * Models via Google APIs that require explicit tool call IDs in function calls/responses.\n */\nexport function requiresToolCallId(modelId: string): boolean {\n\treturn modelId.startsWith(\"claude-\") || modelId.startsWith(\"gpt-oss-\");\n}\n\n/**\n * Convert internal messages to Gemini Content[] format.\n */\nexport function convertMessages<T extends GoogleApiType>(model: Model<T>, context: Context): Content[] {\n\tconst contents: Content[] = [];\n\tconst normalizeToolCallId = (id: string): string => {\n\t\tif (!requiresToolCallId(model.id)) return id;\n\t\treturn id.replace(/[^a-zA-Z0-9_-]/g, \"_\").slice(0, 64);\n\t};\n\n\tconst transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);\n\n\tfor (const msg of transformedMessages) {\n\t\tif (msg.role === \"user\") {\n\t\t\tif (typeof msg.content === \"string\") {\n\t\t\t\tcontents.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tparts: [{ text: sanitizeSurrogates(msg.content) }],\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst parts: Part[] = msg.content.map((item) => {\n\t\t\t\t\tif (item.type === \"text\") {\n\t\t\t\t\t\treturn { text: sanitizeSurrogates(item.text) };\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tinlineData: {\n\t\t\t\t\t\t\t\tmimeType: item.mimeType,\n\t\t\t\t\t\t\t\tdata: item.data,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tconst filteredParts = !model.input.includes(\"image\") ? parts.filter((p) => p.text !== undefined) : parts;\n\t\t\t\tif (filteredParts.length === 0) continue;\n\t\t\t\tcontents.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tparts: filteredParts,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (msg.role === \"assistant\") {\n\t\t\tconst parts: Part[] = [];\n\t\t\t// Check if message is from same provider and model - only then keep thinking blocks\n\t\t\tconst isSameProviderAndModel = msg.provider === model.provider && msg.model === model.id;\n\n\t\t\tfor (const block of msg.content) {\n\t\t\t\tif (block.type === \"text\") {\n\t\t\t\t\t// Skip empty text blocks - they can cause issues with some models (e.g. Claude via Antigravity)\n\t\t\t\t\tif (!block.text || block.text.trim() === \"\") continue;\n\t\t\t\t\tconst thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.textSignature);\n\t\t\t\t\tparts.push({\n\t\t\t\t\t\ttext: sanitizeSurrogates(block.text),\n\t\t\t\t\t\t...(thoughtSignature && { thoughtSignature }),\n\t\t\t\t\t});\n\t\t\t\t} else if (block.type === \"thinking\") {\n\t\t\t\t\t// Skip empty thinking blocks\n\t\t\t\t\tif (!block.thinking || block.thinking.trim() === \"\") continue;\n\t\t\t\t\t// Only keep as thinking block if same provider AND same model\n\t\t\t\t\t// Otherwise convert to plain text (no tags to avoid model mimicking them)\n\t\t\t\t\tif (isSameProviderAndModel) {\n\t\t\t\t\t\tconst thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.thinkingSignature);\n\t\t\t\t\t\tparts.push({\n\t\t\t\t\t\t\tthought: true,\n\t\t\t\t\t\t\ttext: sanitizeSurrogates(block.thinking),\n\t\t\t\t\t\t\t...(thoughtSignature && { thoughtSignature }),\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tparts.push({\n\t\t\t\t\t\t\ttext: sanitizeSurrogates(block.thinking),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\tconst thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.thoughtSignature);\n\t\t\t\t\t// Gemini 3 requires thoughtSignature on all function calls when thinking mode is enabled.\n\t\t\t\t\t// Use the skip_thought_signature_validator sentinel for unsigned function calls\n\t\t\t\t\t// (e.g. replayed from providers without thought signatures like Claude via Antigravity).\n\t\t\t\t\tconst isGemini3 = model.id.toLowerCase().includes(\"gemini-3\");\n\t\t\t\t\tconst effectiveSignature = thoughtSignature || (isGemini3 ? SKIP_THOUGHT_SIGNATURE : undefined);\n\t\t\t\t\tconst part: Part = {\n\t\t\t\t\t\tfunctionCall: {\n\t\t\t\t\t\t\tname: block.name,\n\t\t\t\t\t\t\targs: block.arguments ?? {},\n\t\t\t\t\t\t\t...(requiresToolCallId(model.id) ? { id: block.id } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...(effectiveSignature && { thoughtSignature: effectiveSignature }),\n\t\t\t\t\t};\n\t\t\t\t\tparts.push(part);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (parts.length === 0) continue;\n\t\t\tcontents.push({\n\t\t\t\trole: \"model\",\n\t\t\t\tparts,\n\t\t\t});\n\t\t} else if (msg.role === \"toolResult\") {\n\t\t\t// Extract text and image content\n\t\t\tconst textContent = msg.content.filter((c): c is TextContent => c.type === \"text\");\n\t\t\tconst textResult = textContent.map((c) => c.text).join(\"\\n\");\n\t\t\tconst imageContent = model.input.includes(\"image\")\n\t\t\t\t? msg.content.filter((c): c is ImageContent => c.type === \"image\")\n\t\t\t\t: [];\n\n\t\t\tconst hasText = textResult.length > 0;\n\t\t\tconst hasImages = imageContent.length > 0;\n\n\t\t\t// Gemini 3 supports multimodal function responses with images nested inside functionResponse.parts\n\t\t\t// See: https://ai.google.dev/gemini-api/docs/function-calling#multimodal\n\t\t\t// Older models don't support this, so we put images in a separate user message.\n\t\t\tconst supportsMultimodalFunctionResponse = model.id.includes(\"gemini-3\");\n\n\t\t\t// Use \"output\" key for success, \"error\" key for errors as per SDK documentation\n\t\t\tconst responseValue = hasText ? sanitizeSurrogates(textResult) : hasImages ? \"(see attached image)\" : \"\";\n\n\t\t\tconst imageParts: Part[] = imageContent.map((imageBlock) => ({\n\t\t\t\tinlineData: {\n\t\t\t\t\tmimeType: imageBlock.mimeType,\n\t\t\t\t\tdata: imageBlock.data,\n\t\t\t\t},\n\t\t\t}));\n\n\t\t\tconst includeId = requiresToolCallId(model.id);\n\t\t\tconst functionResponsePart: Part = {\n\t\t\t\tfunctionResponse: {\n\t\t\t\t\tname: msg.toolName,\n\t\t\t\t\tresponse: msg.isError ? { error: responseValue } : { output: responseValue },\n\t\t\t\t\t// Nest images inside functionResponse.parts for Gemini 3\n\t\t\t\t\t...(hasImages && supportsMultimodalFunctionResponse && { parts: imageParts }),\n\t\t\t\t\t...(includeId ? { id: msg.toolCallId } : {}),\n\t\t\t\t},\n\t\t\t};\n\n\t\t\t// Cloud Code Assist API requires all function responses to be in a single user turn.\n\t\t\t// Check if the last content is already a user turn with function responses and merge.\n\t\t\tconst lastContent = contents[contents.length - 1];\n\t\t\tif (lastContent?.role === \"user\" && lastContent.parts?.some((p) => p.functionResponse)) {\n\t\t\t\tlastContent.parts.push(functionResponsePart);\n\t\t\t} else {\n\t\t\t\tcontents.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tparts: [functionResponsePart],\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// For older models, add images in a separate user message\n\t\t\tif (hasImages && !supportsMultimodalFunctionResponse) {\n\t\t\t\tcontents.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tparts: [{ text: \"Tool result image:\" }, ...imageParts],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn contents;\n}\n\n/**\n * Sanitize a JSON Schema for Google's function declarations API.\n * Google's API rejects `patternProperties` and `const` fields which are valid in JSON Schema.\n *\n * This function recursively:\n * - Removes all `patternProperties` fields\n * - Converts `const: \"value\"` to `enum: [\"value\"]` in anyOf/oneOf blocks\n *\n * This is needed for providers like `google-antigravity` when proxying Claude models,\n * since Google Cloud Code Assist uses a restricted subset of JSON Schema.\n */\nexport function sanitizeSchemaForGoogle(schema: unknown): unknown {\n\tif (!schema || typeof schema !== \"object\") {\n\t\treturn schema;\n\t}\n\n\tif (Array.isArray(schema)) {\n\t\treturn schema.map((item) => sanitizeSchemaForGoogle(item));\n\t}\n\n\tconst obj = schema as Record<string, unknown>;\n\tconst sanitized: Record<string, unknown> = {};\n\n\tfor (const [key, value] of Object.entries(obj)) {\n\t\t// Skip patternProperties entirely — not supported by Google's API\n\t\tif (key === \"patternProperties\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Convert const to enum — Google's API rejects the const keyword\n\t\tif (key === \"const\" && typeof value === \"string\") {\n\t\t\tsanitized.enum = [value];\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Recursively sanitize all nested objects and arrays\n\t\tif (typeof value === \"object\") {\n\t\t\tsanitized[key] = sanitizeSchemaForGoogle(value);\n\t\t} else {\n\t\t\tsanitized[key] = value;\n\t\t}\n\t}\n\n\treturn sanitized;\n}\n\n/**\n * Convert tools to Gemini function declarations format.\n *\n * By default uses `parametersJsonSchema` which supports full JSON Schema (including\n * anyOf, oneOf, const, etc.). Set `useParameters` to true to use the legacy `parameters`\n * field instead (OpenAPI 3.03 Schema). This is needed for Cloud Code Assist with Claude\n * models, where the API translates `parameters` into Anthropic's `input_schema`.\n *\n * The schema is automatically sanitized to remove fields not supported by Google's\n * function declarations API (patternProperties, const converted to enum, etc.).\n */\nexport function convertTools(\n\ttools: Tool[],\n\tuseParameters = false,\n): { functionDeclarations: Record<string, unknown>[] }[] | undefined {\n\tif (tools.length === 0) return undefined;\n\treturn [\n\t\t{\n\t\t\tfunctionDeclarations: tools.map((tool) => ({\n\t\t\t\tname: tool.name,\n\t\t\t\tdescription: tool.description,\n\t\t\t\t...(useParameters\n\t\t\t\t\t? { parameters: sanitizeSchemaForGoogle(tool.parameters) }\n\t\t\t\t\t: { parametersJsonSchema: sanitizeSchemaForGoogle(tool.parameters) }),\n\t\t\t})),\n\t\t},\n\t];\n}\n\n/**\n * Map tool choice string to Gemini FunctionCallingConfigMode.\n */\nexport function mapToolChoice(choice: string): FunctionCallingConfigMode {\n\tswitch (choice) {\n\t\tcase \"auto\":\n\t\t\treturn FunctionCallingConfigMode.AUTO;\n\t\tcase \"none\":\n\t\t\treturn FunctionCallingConfigMode.NONE;\n\t\tcase \"any\":\n\t\t\treturn FunctionCallingConfigMode.ANY;\n\t\tdefault:\n\t\t\treturn FunctionCallingConfigMode.AUTO;\n\t}\n}\n\n/**\n * Map Gemini FinishReason to our StopReason.\n */\nexport function mapStopReason(reason: FinishReason): StopReason {\n\tswitch (reason) {\n\t\tcase FinishReason.STOP:\n\t\t\treturn \"stop\";\n\t\tcase FinishReason.MAX_TOKENS:\n\t\t\treturn \"length\";\n\t\tcase FinishReason.BLOCKLIST:\n\t\tcase FinishReason.PROHIBITED_CONTENT:\n\t\tcase FinishReason.SPII:\n\t\tcase FinishReason.SAFETY:\n\t\tcase FinishReason.IMAGE_SAFETY:\n\t\tcase FinishReason.IMAGE_PROHIBITED_CONTENT:\n\t\tcase FinishReason.IMAGE_RECITATION:\n\t\tcase FinishReason.IMAGE_OTHER:\n\t\tcase FinishReason.RECITATION:\n\t\tcase FinishReason.FINISH_REASON_UNSPECIFIED:\n\t\tcase FinishReason.OTHER:\n\t\tcase FinishReason.LANGUAGE:\n\t\tcase FinishReason.MALFORMED_FUNCTION_CALL:\n\t\tcase FinishReason.UNEXPECTED_TOOL_CALL:\n\t\tcase FinishReason.NO_IMAGE:\n\t\t\treturn \"error\";\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = reason;\n\t\t\tthrow new Error(`Unhandled stop reason: ${_exhaustive}`);\n\t\t}\n\t}\n}\n\n/**\n * Map string finish reason to our StopReason (for raw API responses).\n */\nexport function mapStopReasonString(reason: string): StopReason {\n\tswitch (reason) {\n\t\tcase \"STOP\":\n\t\t\treturn \"stop\";\n\t\tcase \"MAX_TOKENS\":\n\t\t\treturn \"length\";\n\t\tdefault:\n\t\t\treturn \"error\";\n\t}\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=google-shared.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-shared.test.d.ts","sourceRoot":"","sources":["../../src/providers/google-shared.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,125 @@
1
+ import { describe, it } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { sanitizeSchemaForGoogle } from "./google-shared.js";
4
+ // ═══════════════════════════════════════════════════════════════════════════
5
+ // sanitizeSchemaForGoogle
6
+ // ═══════════════════════════════════════════════════════════════════════════
7
+ describe("sanitizeSchemaForGoogle", () => {
8
+ it("passes through primitives unchanged", () => {
9
+ assert.equal(sanitizeSchemaForGoogle(null), null);
10
+ assert.equal(sanitizeSchemaForGoogle(42), 42);
11
+ assert.equal(sanitizeSchemaForGoogle("hello"), "hello");
12
+ assert.equal(sanitizeSchemaForGoogle(true), true);
13
+ });
14
+ it("passes through a valid schema with no banned fields", () => {
15
+ const schema = {
16
+ type: "object",
17
+ properties: {
18
+ name: { type: "string" },
19
+ age: { type: "number" },
20
+ },
21
+ required: ["name"],
22
+ };
23
+ assert.deepEqual(sanitizeSchemaForGoogle(schema), schema);
24
+ });
25
+ it("removes top-level patternProperties", () => {
26
+ const schema = {
27
+ type: "object",
28
+ patternProperties: { "^S_": { type: "string" } },
29
+ properties: { foo: { type: "string" } },
30
+ };
31
+ const result = sanitizeSchemaForGoogle(schema);
32
+ assert.ok(!("patternProperties" in result));
33
+ assert.deepEqual(result.properties, { foo: { type: "string" } });
34
+ });
35
+ it("removes nested patternProperties", () => {
36
+ const schema = {
37
+ type: "object",
38
+ properties: {
39
+ nested: {
40
+ type: "object",
41
+ patternProperties: { ".*": { type: "string" } },
42
+ },
43
+ },
44
+ };
45
+ const result = sanitizeSchemaForGoogle(schema);
46
+ assert.ok(!("patternProperties" in result.properties.nested));
47
+ });
48
+ it("converts top-level const to enum", () => {
49
+ const schema = { const: "fixed-value" };
50
+ const result = sanitizeSchemaForGoogle(schema);
51
+ assert.deepEqual(result.enum, ["fixed-value"]);
52
+ assert.ok(!("const" in result));
53
+ });
54
+ it("converts const to enum inside anyOf", () => {
55
+ const schema = {
56
+ anyOf: [{ const: "a" }, { const: "b" }, { type: "string" }],
57
+ };
58
+ const result = sanitizeSchemaForGoogle(schema);
59
+ assert.deepEqual(result.anyOf[0], { enum: ["a"] });
60
+ assert.deepEqual(result.anyOf[1], { enum: ["b"] });
61
+ assert.deepEqual(result.anyOf[2], { type: "string" });
62
+ });
63
+ it("converts const to enum inside oneOf", () => {
64
+ const schema = {
65
+ oneOf: [{ const: "x" }, { const: "y" }],
66
+ };
67
+ const result = sanitizeSchemaForGoogle(schema);
68
+ assert.deepEqual(result.oneOf[0], { enum: ["x"] });
69
+ assert.deepEqual(result.oneOf[1], { enum: ["y"] });
70
+ });
71
+ it("recursively sanitizes deeply nested schemas", () => {
72
+ const schema = {
73
+ type: "object",
74
+ properties: {
75
+ level1: {
76
+ type: "object",
77
+ properties: {
78
+ level2: {
79
+ anyOf: [{ const: "deep" }, { type: "null" }],
80
+ patternProperties: { ".*": { type: "string" } },
81
+ },
82
+ },
83
+ },
84
+ },
85
+ };
86
+ const result = sanitizeSchemaForGoogle(schema);
87
+ const level2 = result.properties.level1.properties.level2;
88
+ assert.deepEqual(level2.anyOf[0], { enum: ["deep"] });
89
+ assert.ok(!("patternProperties" in level2));
90
+ });
91
+ it("sanitizes items in array schemas", () => {
92
+ const schema = {
93
+ type: "array",
94
+ items: {
95
+ anyOf: [{ const: "foo" }, { type: "string" }],
96
+ },
97
+ };
98
+ const result = sanitizeSchemaForGoogle(schema);
99
+ assert.deepEqual(result.items.anyOf[0], { enum: ["foo"] });
100
+ });
101
+ it("sanitizes arrays of schemas", () => {
102
+ const input = [{ const: "a" }, { const: "b" }];
103
+ const result = sanitizeSchemaForGoogle(input);
104
+ assert.deepEqual(result[0], { enum: ["a"] });
105
+ assert.deepEqual(result[1], { enum: ["b"] });
106
+ });
107
+ it("preserves non-string const values unchanged", () => {
108
+ // Only string const values are converted; number const is passed through
109
+ const schema = { const: 42 };
110
+ const result = sanitizeSchemaForGoogle(schema);
111
+ assert.equal(result.const, 42);
112
+ assert.ok(!("enum" in result));
113
+ });
114
+ it("sanitizes additionalProperties", () => {
115
+ const schema = {
116
+ type: "object",
117
+ additionalProperties: {
118
+ patternProperties: { "^x-": { type: "string" } },
119
+ },
120
+ };
121
+ const result = sanitizeSchemaForGoogle(schema);
122
+ assert.ok(!("patternProperties" in result.additionalProperties));
123
+ });
124
+ });
125
+ //# sourceMappingURL=google-shared.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-shared.test.js","sourceRoot":"","sources":["../../src/providers/google-shared.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport { sanitizeSchemaForGoogle } from \"./google-shared.js\";\n\n// ═══════════════════════════════════════════════════════════════════════════\n// sanitizeSchemaForGoogle\n// ═══════════════════════════════════════════════════════════════════════════\n\ndescribe(\"sanitizeSchemaForGoogle\", () => {\n\tit(\"passes through primitives unchanged\", () => {\n\t\tassert.equal(sanitizeSchemaForGoogle(null), null);\n\t\tassert.equal(sanitizeSchemaForGoogle(42), 42);\n\t\tassert.equal(sanitizeSchemaForGoogle(\"hello\"), \"hello\");\n\t\tassert.equal(sanitizeSchemaForGoogle(true), true);\n\t});\n\n\tit(\"passes through a valid schema with no banned fields\", () => {\n\t\tconst schema = {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tname: { type: \"string\" },\n\t\t\t\tage: { type: \"number\" },\n\t\t\t},\n\t\t\trequired: [\"name\"],\n\t\t};\n\t\tassert.deepEqual(sanitizeSchemaForGoogle(schema), schema);\n\t});\n\n\tit(\"removes top-level patternProperties\", () => {\n\t\tconst schema = {\n\t\t\ttype: \"object\",\n\t\t\tpatternProperties: { \"^S_\": { type: \"string\" } },\n\t\t\tproperties: { foo: { type: \"string\" } },\n\t\t};\n\t\tconst result = sanitizeSchemaForGoogle(schema) as Record<string, unknown>;\n\t\tassert.ok(!(\"patternProperties\" in result));\n\t\tassert.deepEqual(result.properties, { foo: { type: \"string\" } });\n\t});\n\n\tit(\"removes nested patternProperties\", () => {\n\t\tconst schema = {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tnested: {\n\t\t\t\t\ttype: \"object\",\n\t\t\t\t\tpatternProperties: { \".*\": { type: \"string\" } },\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t\tconst result = sanitizeSchemaForGoogle(schema) as any;\n\t\tassert.ok(!(\"patternProperties\" in result.properties.nested));\n\t});\n\n\tit(\"converts top-level const to enum\", () => {\n\t\tconst schema = { const: \"fixed-value\" };\n\t\tconst result = sanitizeSchemaForGoogle(schema) as Record<string, unknown>;\n\t\tassert.deepEqual(result.enum, [\"fixed-value\"]);\n\t\tassert.ok(!(\"const\" in result));\n\t});\n\n\tit(\"converts const to enum inside anyOf\", () => {\n\t\tconst schema = {\n\t\t\tanyOf: [{ const: \"a\" }, { const: \"b\" }, { type: \"string\" }],\n\t\t};\n\t\tconst result = sanitizeSchemaForGoogle(schema) as any;\n\t\tassert.deepEqual(result.anyOf[0], { enum: [\"a\"] });\n\t\tassert.deepEqual(result.anyOf[1], { enum: [\"b\"] });\n\t\tassert.deepEqual(result.anyOf[2], { type: \"string\" });\n\t});\n\n\tit(\"converts const to enum inside oneOf\", () => {\n\t\tconst schema = {\n\t\t\toneOf: [{ const: \"x\" }, { const: \"y\" }],\n\t\t};\n\t\tconst result = sanitizeSchemaForGoogle(schema) as any;\n\t\tassert.deepEqual(result.oneOf[0], { enum: [\"x\"] });\n\t\tassert.deepEqual(result.oneOf[1], { enum: [\"y\"] });\n\t});\n\n\tit(\"recursively sanitizes deeply nested schemas\", () => {\n\t\tconst schema = {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tlevel1: {\n\t\t\t\t\ttype: \"object\",\n\t\t\t\t\tproperties: {\n\t\t\t\t\t\tlevel2: {\n\t\t\t\t\t\t\tanyOf: [{ const: \"deep\" }, { type: \"null\" }],\n\t\t\t\t\t\t\tpatternProperties: { \".*\": { type: \"string\" } },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t\tconst result = sanitizeSchemaForGoogle(schema) as any;\n\t\tconst level2 = result.properties.level1.properties.level2;\n\t\tassert.deepEqual(level2.anyOf[0], { enum: [\"deep\"] });\n\t\tassert.ok(!(\"patternProperties\" in level2));\n\t});\n\n\tit(\"sanitizes items in array schemas\", () => {\n\t\tconst schema = {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\tanyOf: [{ const: \"foo\" }, { type: \"string\" }],\n\t\t\t},\n\t\t};\n\t\tconst result = sanitizeSchemaForGoogle(schema) as any;\n\t\tassert.deepEqual(result.items.anyOf[0], { enum: [\"foo\"] });\n\t});\n\n\tit(\"sanitizes arrays of schemas\", () => {\n\t\tconst input = [{ const: \"a\" }, { const: \"b\" }];\n\t\tconst result = sanitizeSchemaForGoogle(input) as any[];\n\t\tassert.deepEqual(result[0], { enum: [\"a\"] });\n\t\tassert.deepEqual(result[1], { enum: [\"b\"] });\n\t});\n\n\tit(\"preserves non-string const values unchanged\", () => {\n\t\t// Only string const values are converted; number const is passed through\n\t\tconst schema = { const: 42 };\n\t\tconst result = sanitizeSchemaForGoogle(schema) as Record<string, unknown>;\n\t\tassert.equal(result.const, 42);\n\t\tassert.ok(!(\"enum\" in result));\n\t});\n\n\tit(\"sanitizes additionalProperties\", () => {\n\t\tconst schema = {\n\t\t\ttype: \"object\",\n\t\t\tadditionalProperties: {\n\t\t\t\tpatternProperties: { \"^x-\": { type: \"string\" } },\n\t\t\t},\n\t\t};\n\t\tconst result = sanitizeSchemaForGoogle(schema) as any;\n\t\tassert.ok(!(\"patternProperties\" in result.additionalProperties));\n\t});\n});\n"]}