@llumiverse/drivers 1.3.0 → 1.4.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 (409) hide show
  1. package/lib/{types/adobe → adobe}/firefly.d.ts +2 -1
  2. package/lib/adobe/firefly.d.ts.map +1 -0
  3. package/lib/adobe/firefly.js +120 -0
  4. package/lib/adobe/firefly.js.map +1 -0
  5. package/lib/{types/anthropic → anthropic}/index.d.ts +4 -2
  6. package/lib/anthropic/index.d.ts.map +1 -0
  7. package/lib/{esm/anthropic → anthropic}/index.js +19 -8
  8. package/lib/anthropic/index.js.map +1 -0
  9. package/lib/{types/azure → azure}/azure_foundry.d.ts +9 -7
  10. package/lib/azure/azure_foundry.d.ts.map +1 -0
  11. package/lib/{esm/azure → azure}/azure_foundry.js +138 -124
  12. package/lib/azure/azure_foundry.js.map +1 -0
  13. package/lib/{types/bedrock → bedrock}/converse.d.ts +2 -2
  14. package/lib/bedrock/converse.d.ts.map +1 -0
  15. package/lib/{esm/bedrock → bedrock}/converse.js +86 -79
  16. package/lib/bedrock/converse.js.map +1 -0
  17. package/lib/bedrock/embeddings.d.ts +4 -0
  18. package/lib/bedrock/embeddings.d.ts.map +1 -0
  19. package/lib/bedrock/embeddings.js +359 -0
  20. package/lib/bedrock/embeddings.js.map +1 -0
  21. package/lib/{types/bedrock → bedrock}/index.d.ts +33 -9
  22. package/lib/bedrock/index.d.ts.map +1 -0
  23. package/lib/{esm/bedrock → bedrock}/index.js +599 -324
  24. package/lib/bedrock/index.js.map +1 -0
  25. package/lib/{types/bedrock → bedrock}/nova-image-payload.d.ts +5 -5
  26. package/lib/bedrock/nova-image-payload.d.ts.map +1 -0
  27. package/lib/{esm/bedrock → bedrock}/nova-image-payload.js +31 -36
  28. package/lib/bedrock/nova-image-payload.js.map +1 -0
  29. package/lib/{types/bedrock → bedrock}/payloads.d.ts +1 -1
  30. package/lib/bedrock/payloads.d.ts.map +1 -0
  31. package/lib/{cjs/bedrock → bedrock}/payloads.js.map +1 -1
  32. package/lib/{types/bedrock → bedrock}/s3.d.ts +3 -2
  33. package/lib/bedrock/s3.d.ts.map +1 -0
  34. package/lib/{esm/bedrock → bedrock}/s3.js +27 -23
  35. package/lib/bedrock/s3.js.map +1 -0
  36. package/lib/{types/bedrock → bedrock}/twelvelabs.d.ts +8 -9
  37. package/lib/bedrock/twelvelabs.d.ts.map +1 -0
  38. package/lib/{esm/bedrock → bedrock}/twelvelabs.js +17 -21
  39. package/lib/bedrock/twelvelabs.js.map +1 -0
  40. package/lib/{types/groq → groq}/index.d.ts +6 -4
  41. package/lib/groq/index.d.ts.map +1 -0
  42. package/lib/{esm/groq → groq}/index.js +72 -39
  43. package/lib/groq/index.js.map +1 -0
  44. package/lib/{types/huggingface_ie.d.ts → huggingface_ie.d.ts} +4 -3
  45. package/lib/huggingface_ie.d.ts.map +1 -0
  46. package/lib/{esm/huggingface_ie.js → huggingface_ie.js} +32 -31
  47. package/lib/huggingface_ie.js.map +1 -0
  48. package/lib/index.d.ts +16 -0
  49. package/lib/index.d.ts.map +1 -0
  50. package/lib/index.js +16 -0
  51. package/lib/index.js.map +1 -0
  52. package/lib/{types/mistral → mistral}/index.d.ts +6 -5
  53. package/lib/mistral/index.d.ts.map +1 -0
  54. package/lib/{esm/mistral → mistral}/index.js +66 -38
  55. package/lib/mistral/index.js.map +1 -0
  56. package/lib/{types/mistral → mistral}/types.d.ts +1 -0
  57. package/lib/mistral/types.d.ts.map +1 -0
  58. package/lib/mistral/types.js.map +1 -0
  59. package/lib/{types/openai → openai}/azure_openai.d.ts +5 -4
  60. package/lib/openai/azure_openai.d.ts.map +1 -0
  61. package/lib/{esm/openai → openai}/azure_openai.js +17 -14
  62. package/lib/openai/azure_openai.js.map +1 -0
  63. package/lib/openai/drivers.d.ts +4 -0
  64. package/lib/openai/drivers.d.ts.map +1 -0
  65. package/lib/openai/drivers.js +9 -0
  66. package/lib/openai/drivers.js.map +1 -0
  67. package/lib/{types/openai → openai}/index.d.ts +16 -5
  68. package/lib/openai/index.d.ts.map +1 -0
  69. package/lib/{esm/openai → openai}/index.js +242 -141
  70. package/lib/openai/index.js.map +1 -0
  71. package/lib/{types/openai → openai}/openai.d.ts +3 -3
  72. package/lib/openai/openai.d.ts.map +1 -0
  73. package/lib/openai/openai.js +15 -0
  74. package/lib/openai/openai.js.map +1 -0
  75. package/lib/{types/openai → openai}/openai_compatible.d.ts +3 -3
  76. package/lib/openai/openai_compatible.d.ts.map +1 -0
  77. package/lib/{esm/openai → openai}/openai_compatible.js +14 -11
  78. package/lib/openai/openai_compatible.js.map +1 -0
  79. package/lib/{types/openai → openai}/openai_format.d.ts +3 -2
  80. package/lib/openai/openai_format.d.ts.map +1 -0
  81. package/lib/{esm/openai → openai}/openai_format.js +66 -24
  82. package/lib/openai/openai_format.js.map +1 -0
  83. package/lib/{types/replicate.d.ts → replicate.d.ts} +3 -2
  84. package/lib/replicate.d.ts.map +1 -0
  85. package/lib/{esm/replicate.js → replicate.js} +59 -49
  86. package/lib/replicate.js.map +1 -0
  87. package/lib/{types/shared → shared}/claude-messages.d.ts +25 -1
  88. package/lib/shared/claude-messages.d.ts.map +1 -0
  89. package/lib/{esm/shared → shared}/claude-messages.js +212 -59
  90. package/lib/shared/claude-messages.js.map +1 -0
  91. package/lib/{types/shared → shared}/claude-thinking.d.ts +1 -1
  92. package/lib/shared/claude-thinking.d.ts.map +1 -0
  93. package/lib/{esm/shared → shared}/claude-thinking.js +5 -7
  94. package/lib/shared/claude-thinking.js.map +1 -0
  95. package/lib/shared/debug-prompt.d.ts +5 -0
  96. package/lib/shared/debug-prompt.d.ts.map +1 -0
  97. package/lib/shared/debug-prompt.js +25 -0
  98. package/lib/shared/debug-prompt.js.map +1 -0
  99. package/lib/{types/test-driver → test-driver}/TestErrorCompletionStream.d.ts +1 -1
  100. package/lib/test-driver/TestErrorCompletionStream.d.ts.map +1 -0
  101. package/lib/test-driver/TestErrorCompletionStream.js +16 -0
  102. package/lib/test-driver/TestErrorCompletionStream.js.map +1 -0
  103. package/lib/{types/test-driver → test-driver}/TestValidationErrorCompletionStream.d.ts +1 -1
  104. package/lib/test-driver/TestValidationErrorCompletionStream.d.ts.map +1 -0
  105. package/lib/{esm/test-driver → test-driver}/TestValidationErrorCompletionStream.js +4 -4
  106. package/lib/test-driver/TestValidationErrorCompletionStream.js.map +1 -0
  107. package/lib/{types/test-driver → test-driver}/index.d.ts +3 -3
  108. package/lib/test-driver/index.d.ts.map +1 -0
  109. package/lib/{esm/test-driver → test-driver}/index.js +20 -20
  110. package/lib/test-driver/index.js.map +1 -0
  111. package/lib/{types/test-driver → test-driver}/utils.d.ts +1 -1
  112. package/lib/test-driver/utils.d.ts.map +1 -0
  113. package/lib/{esm/test-driver → test-driver}/utils.js +4 -4
  114. package/lib/test-driver/utils.js.map +1 -0
  115. package/lib/togetherai/index.d.ts +15 -0
  116. package/lib/togetherai/index.d.ts.map +1 -0
  117. package/lib/togetherai/index.js +54 -0
  118. package/lib/togetherai/index.js.map +1 -0
  119. package/lib/{types/togetherai → togetherai}/interfaces.d.ts +1 -1
  120. package/lib/togetherai/interfaces.d.ts.map +1 -0
  121. package/lib/{cjs/watsonx → togetherai}/interfaces.js.map +1 -1
  122. package/lib/vertexai/debug.d.ts +2 -0
  123. package/lib/vertexai/debug.d.ts.map +1 -0
  124. package/lib/{esm/vertexai → vertexai}/debug.js +1 -1
  125. package/lib/vertexai/debug.js.map +1 -0
  126. package/lib/vertexai/embeddings/embed-legacy-multimodal.d.ts +9 -0
  127. package/lib/vertexai/embeddings/embed-legacy-multimodal.d.ts.map +1 -0
  128. package/lib/vertexai/embeddings/embed-legacy-multimodal.js +141 -0
  129. package/lib/vertexai/embeddings/embed-legacy-multimodal.js.map +1 -0
  130. package/lib/vertexai/embeddings/embed.d.ts +13 -0
  131. package/lib/vertexai/embeddings/embed.d.ts.map +1 -0
  132. package/lib/vertexai/embeddings/embed.js +162 -0
  133. package/lib/vertexai/embeddings/embed.js.map +1 -0
  134. package/lib/vertexai/embeddings/source-utils.d.ts +9 -0
  135. package/lib/vertexai/embeddings/source-utils.d.ts.map +1 -0
  136. package/lib/vertexai/embeddings/source-utils.js +18 -0
  137. package/lib/vertexai/embeddings/source-utils.js.map +1 -0
  138. package/lib/{types/vertexai → vertexai}/index.d.ts +31 -19
  139. package/lib/vertexai/index.d.ts.map +1 -0
  140. package/lib/{esm/vertexai → vertexai}/index.js +221 -159
  141. package/lib/vertexai/index.js.map +1 -0
  142. package/lib/{types/vertexai → vertexai}/models/claude.d.ts +4 -4
  143. package/lib/vertexai/models/claude.d.ts.map +1 -0
  144. package/lib/{esm/vertexai → vertexai}/models/claude.js +17 -20
  145. package/lib/vertexai/models/claude.js.map +1 -0
  146. package/lib/{types/vertexai → vertexai}/models/gemini.d.ts +28 -4
  147. package/lib/vertexai/models/gemini.d.ts.map +1 -0
  148. package/lib/{esm/vertexai → vertexai}/models/gemini.js +238 -116
  149. package/lib/vertexai/models/gemini.js.map +1 -0
  150. package/lib/{types/vertexai → vertexai}/models/imagen.d.ts +12 -11
  151. package/lib/vertexai/models/imagen.d.ts.map +1 -0
  152. package/lib/{esm/vertexai → vertexai}/models/imagen.js +74 -47
  153. package/lib/vertexai/models/imagen.js.map +1 -0
  154. package/lib/{types/vertexai → vertexai}/models/llama.d.ts +4 -4
  155. package/lib/vertexai/models/llama.d.ts.map +1 -0
  156. package/lib/{esm/vertexai → vertexai}/models/llama.js +37 -33
  157. package/lib/vertexai/models/llama.js.map +1 -0
  158. package/lib/vertexai/models.d.ts +21 -0
  159. package/lib/vertexai/models.d.ts.map +1 -0
  160. package/lib/{esm/vertexai → vertexai}/models.js +12 -9
  161. package/lib/vertexai/models.js.map +1 -0
  162. package/lib/{types/watsonx → watsonx}/index.d.ts +4 -3
  163. package/lib/watsonx/index.d.ts.map +1 -0
  164. package/lib/{esm/watsonx → watsonx}/index.js +69 -41
  165. package/lib/watsonx/index.js.map +1 -0
  166. package/lib/watsonx/interfaces.d.ts.map +1 -0
  167. package/lib/{esm/watsonx → watsonx}/interfaces.js.map +1 -1
  168. package/lib/{types/xai → xai}/index.d.ts +4 -4
  169. package/lib/xai/index.d.ts.map +1 -0
  170. package/lib/{esm/xai → xai}/index.js +22 -18
  171. package/lib/xai/index.js.map +1 -0
  172. package/package.json +87 -36
  173. package/src/adobe/firefly.ts +60 -43
  174. package/src/anthropic/index.ts +37 -20
  175. package/src/azure/azure_foundry.ts +210 -165
  176. package/src/bedrock/converse.ts +124 -101
  177. package/src/bedrock/embeddings.test.ts +508 -0
  178. package/src/bedrock/embeddings.ts +517 -0
  179. package/src/bedrock/error-handling.test.ts +62 -14
  180. package/src/bedrock/index.ts +832 -466
  181. package/src/bedrock/nova-image-payload.ts +98 -91
  182. package/src/bedrock/payloads.ts +9 -9
  183. package/src/bedrock/s3.test.ts +39 -0
  184. package/src/bedrock/s3.ts +57 -38
  185. package/src/bedrock/streaming-tool-use.test.ts +86 -69
  186. package/src/bedrock/twelvelabs.ts +35 -32
  187. package/src/groq/index.ts +143 -60
  188. package/src/http-timeout-wiring.test.ts +263 -0
  189. package/src/huggingface_ie.ts +45 -61
  190. package/src/index.ts +15 -16
  191. package/src/mistral/index.ts +97 -48
  192. package/src/mistral/types.ts +13 -12
  193. package/src/openai/azure_openai.ts +35 -27
  194. package/src/openai/drivers.ts +9 -0
  195. package/src/openai/error-handling.test.ts +308 -113
  196. package/src/openai/index.ts +378 -248
  197. package/src/openai/openai.ts +6 -13
  198. package/src/openai/openai_compatible.ts +35 -25
  199. package/src/openai/openai_format.ts +90 -40
  200. package/src/replicate.ts +108 -86
  201. package/src/shared/claude-messages.test.ts +37 -0
  202. package/src/shared/claude-messages.ts +303 -97
  203. package/src/shared/claude-thinking.ts +6 -12
  204. package/src/shared/debug-prompt.ts +28 -0
  205. package/src/test-driver/TestErrorCompletionStream.ts +9 -10
  206. package/src/test-driver/TestValidationErrorCompletionStream.ts +9 -10
  207. package/src/test-driver/index.ts +43 -27
  208. package/src/test-driver/utils.ts +8 -8
  209. package/src/togetherai/index.test.ts +32 -0
  210. package/src/togetherai/index.ts +64 -128
  211. package/src/togetherai/interfaces.ts +5 -5
  212. package/src/vertexai/debug.ts +3 -3
  213. package/src/vertexai/embeddings/embed-legacy-multimodal.ts +211 -0
  214. package/src/vertexai/embeddings/embed.ts +206 -0
  215. package/src/vertexai/embeddings/embeddings.test.ts +497 -0
  216. package/src/vertexai/embeddings/source-utils.test.ts +54 -0
  217. package/src/vertexai/embeddings/source-utils.ts +29 -0
  218. package/src/vertexai/index.ts +331 -244
  219. package/src/vertexai/models/claude-error-handling.test.ts +83 -36
  220. package/src/vertexai/models/claude-streaming-spacing.test.ts +82 -75
  221. package/src/vertexai/models/claude.ts +55 -40
  222. package/src/vertexai/models/gemini-conversation-mutation.test.ts +65 -23
  223. package/src/vertexai/models/gemini-error-handling.test.ts +126 -10
  224. package/src/vertexai/models/gemini-orphaned-tool-result.test.ts +118 -0
  225. package/src/vertexai/models/gemini.ts +349 -172
  226. package/src/vertexai/models/imagen.ts +164 -100
  227. package/src/vertexai/models/llama.ts +70 -48
  228. package/src/vertexai/models.ts +36 -16
  229. package/src/watsonx/index.ts +101 -65
  230. package/src/watsonx/interfaces.ts +10 -15
  231. package/src/xai/index.ts +30 -30
  232. package/lib/cjs/adobe/firefly.js +0 -120
  233. package/lib/cjs/adobe/firefly.js.map +0 -1
  234. package/lib/cjs/anthropic/index.js +0 -64
  235. package/lib/cjs/anthropic/index.js.map +0 -1
  236. package/lib/cjs/azure/azure_foundry.js +0 -432
  237. package/lib/cjs/azure/azure_foundry.js.map +0 -1
  238. package/lib/cjs/bedrock/converse.js +0 -359
  239. package/lib/cjs/bedrock/converse.js.map +0 -1
  240. package/lib/cjs/bedrock/index.js +0 -1508
  241. package/lib/cjs/bedrock/index.js.map +0 -1
  242. package/lib/cjs/bedrock/nova-image-payload.js +0 -207
  243. package/lib/cjs/bedrock/nova-image-payload.js.map +0 -1
  244. package/lib/cjs/bedrock/payloads.js +0 -3
  245. package/lib/cjs/bedrock/s3.js +0 -107
  246. package/lib/cjs/bedrock/s3.js.map +0 -1
  247. package/lib/cjs/bedrock/twelvelabs.js +0 -87
  248. package/lib/cjs/bedrock/twelvelabs.js.map +0 -1
  249. package/lib/cjs/groq/index.js +0 -328
  250. package/lib/cjs/groq/index.js.map +0 -1
  251. package/lib/cjs/huggingface_ie.js +0 -201
  252. package/lib/cjs/huggingface_ie.js.map +0 -1
  253. package/lib/cjs/index.js +0 -32
  254. package/lib/cjs/index.js.map +0 -1
  255. package/lib/cjs/mistral/index.js +0 -176
  256. package/lib/cjs/mistral/index.js.map +0 -1
  257. package/lib/cjs/mistral/types.js +0 -83
  258. package/lib/cjs/mistral/types.js.map +0 -1
  259. package/lib/cjs/openai/azure_openai.js +0 -72
  260. package/lib/cjs/openai/azure_openai.js.map +0 -1
  261. package/lib/cjs/openai/index.js +0 -1135
  262. package/lib/cjs/openai/index.js.map +0 -1
  263. package/lib/cjs/openai/openai.js +0 -21
  264. package/lib/cjs/openai/openai.js.map +0 -1
  265. package/lib/cjs/openai/openai_compatible.js +0 -63
  266. package/lib/cjs/openai/openai_compatible.js.map +0 -1
  267. package/lib/cjs/openai/openai_format.js +0 -131
  268. package/lib/cjs/openai/openai_format.js.map +0 -1
  269. package/lib/cjs/package.json +0 -3
  270. package/lib/cjs/replicate.js +0 -275
  271. package/lib/cjs/replicate.js.map +0 -1
  272. package/lib/cjs/shared/claude-messages.js +0 -737
  273. package/lib/cjs/shared/claude-messages.js.map +0 -1
  274. package/lib/cjs/shared/claude-thinking.js +0 -60
  275. package/lib/cjs/shared/claude-thinking.js.map +0 -1
  276. package/lib/cjs/test-driver/TestErrorCompletionStream.js +0 -20
  277. package/lib/cjs/test-driver/TestErrorCompletionStream.js.map +0 -1
  278. package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js +0 -24
  279. package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js.map +0 -1
  280. package/lib/cjs/test-driver/index.js +0 -109
  281. package/lib/cjs/test-driver/index.js.map +0 -1
  282. package/lib/cjs/test-driver/utils.js +0 -30
  283. package/lib/cjs/test-driver/utils.js.map +0 -1
  284. package/lib/cjs/togetherai/index.js +0 -126
  285. package/lib/cjs/togetherai/index.js.map +0 -1
  286. package/lib/cjs/togetherai/interfaces.js +0 -3
  287. package/lib/cjs/togetherai/interfaces.js.map +0 -1
  288. package/lib/cjs/vertexai/debug.js +0 -12
  289. package/lib/cjs/vertexai/debug.js.map +0 -1
  290. package/lib/cjs/vertexai/embeddings/embeddings-image.js +0 -27
  291. package/lib/cjs/vertexai/embeddings/embeddings-image.js.map +0 -1
  292. package/lib/cjs/vertexai/embeddings/embeddings-text.js +0 -23
  293. package/lib/cjs/vertexai/embeddings/embeddings-text.js.map +0 -1
  294. package/lib/cjs/vertexai/index.js +0 -644
  295. package/lib/cjs/vertexai/index.js.map +0 -1
  296. package/lib/cjs/vertexai/models/claude.js +0 -72
  297. package/lib/cjs/vertexai/models/claude.js.map +0 -1
  298. package/lib/cjs/vertexai/models/gemini.js +0 -864
  299. package/lib/cjs/vertexai/models/gemini.js.map +0 -1
  300. package/lib/cjs/vertexai/models/imagen.js +0 -303
  301. package/lib/cjs/vertexai/models/imagen.js.map +0 -1
  302. package/lib/cjs/vertexai/models/llama.js +0 -183
  303. package/lib/cjs/vertexai/models/llama.js.map +0 -1
  304. package/lib/cjs/vertexai/models.js +0 -35
  305. package/lib/cjs/vertexai/models.js.map +0 -1
  306. package/lib/cjs/watsonx/index.js +0 -161
  307. package/lib/cjs/watsonx/index.js.map +0 -1
  308. package/lib/cjs/watsonx/interfaces.js +0 -3
  309. package/lib/cjs/xai/index.js +0 -65
  310. package/lib/cjs/xai/index.js.map +0 -1
  311. package/lib/esm/adobe/firefly.js +0 -116
  312. package/lib/esm/adobe/firefly.js.map +0 -1
  313. package/lib/esm/anthropic/index.js.map +0 -1
  314. package/lib/esm/azure/azure_foundry.js.map +0 -1
  315. package/lib/esm/bedrock/converse.js.map +0 -1
  316. package/lib/esm/bedrock/index.js.map +0 -1
  317. package/lib/esm/bedrock/nova-image-payload.js.map +0 -1
  318. package/lib/esm/bedrock/payloads.js.map +0 -1
  319. package/lib/esm/bedrock/s3.js.map +0 -1
  320. package/lib/esm/bedrock/twelvelabs.js.map +0 -1
  321. package/lib/esm/groq/index.js.map +0 -1
  322. package/lib/esm/huggingface_ie.js.map +0 -1
  323. package/lib/esm/index.js +0 -16
  324. package/lib/esm/index.js.map +0 -1
  325. package/lib/esm/mistral/index.js.map +0 -1
  326. package/lib/esm/mistral/types.js.map +0 -1
  327. package/lib/esm/openai/azure_openai.js.map +0 -1
  328. package/lib/esm/openai/index.js.map +0 -1
  329. package/lib/esm/openai/openai.js +0 -14
  330. package/lib/esm/openai/openai.js.map +0 -1
  331. package/lib/esm/openai/openai_compatible.js.map +0 -1
  332. package/lib/esm/openai/openai_format.js.map +0 -1
  333. package/lib/esm/replicate.js.map +0 -1
  334. package/lib/esm/shared/claude-messages.js.map +0 -1
  335. package/lib/esm/shared/claude-thinking.js.map +0 -1
  336. package/lib/esm/test-driver/TestErrorCompletionStream.js +0 -16
  337. package/lib/esm/test-driver/TestErrorCompletionStream.js.map +0 -1
  338. package/lib/esm/test-driver/TestValidationErrorCompletionStream.js.map +0 -1
  339. package/lib/esm/test-driver/index.js.map +0 -1
  340. package/lib/esm/test-driver/utils.js.map +0 -1
  341. package/lib/esm/togetherai/index.js +0 -122
  342. package/lib/esm/togetherai/index.js.map +0 -1
  343. package/lib/esm/togetherai/interfaces.js.map +0 -1
  344. package/lib/esm/vertexai/debug.js.map +0 -1
  345. package/lib/esm/vertexai/embeddings/embeddings-image.js +0 -24
  346. package/lib/esm/vertexai/embeddings/embeddings-image.js.map +0 -1
  347. package/lib/esm/vertexai/embeddings/embeddings-text.js +0 -20
  348. package/lib/esm/vertexai/embeddings/embeddings-text.js.map +0 -1
  349. package/lib/esm/vertexai/index.js.map +0 -1
  350. package/lib/esm/vertexai/models/claude.js.map +0 -1
  351. package/lib/esm/vertexai/models/gemini.js.map +0 -1
  352. package/lib/esm/vertexai/models/imagen.js.map +0 -1
  353. package/lib/esm/vertexai/models/llama.js.map +0 -1
  354. package/lib/esm/vertexai/models.js.map +0 -1
  355. package/lib/esm/watsonx/index.js.map +0 -1
  356. package/lib/esm/xai/index.js.map +0 -1
  357. package/lib/types/adobe/firefly.d.ts.map +0 -1
  358. package/lib/types/anthropic/index.d.ts.map +0 -1
  359. package/lib/types/azure/azure_foundry.d.ts.map +0 -1
  360. package/lib/types/bedrock/converse.d.ts.map +0 -1
  361. package/lib/types/bedrock/index.d.ts.map +0 -1
  362. package/lib/types/bedrock/nova-image-payload.d.ts.map +0 -1
  363. package/lib/types/bedrock/payloads.d.ts.map +0 -1
  364. package/lib/types/bedrock/s3.d.ts.map +0 -1
  365. package/lib/types/bedrock/twelvelabs.d.ts.map +0 -1
  366. package/lib/types/groq/index.d.ts.map +0 -1
  367. package/lib/types/huggingface_ie.d.ts.map +0 -1
  368. package/lib/types/index.d.ts +0 -16
  369. package/lib/types/index.d.ts.map +0 -1
  370. package/lib/types/mistral/index.d.ts.map +0 -1
  371. package/lib/types/mistral/types.d.ts.map +0 -1
  372. package/lib/types/openai/azure_openai.d.ts.map +0 -1
  373. package/lib/types/openai/index.d.ts.map +0 -1
  374. package/lib/types/openai/openai.d.ts.map +0 -1
  375. package/lib/types/openai/openai_compatible.d.ts.map +0 -1
  376. package/lib/types/openai/openai_format.d.ts.map +0 -1
  377. package/lib/types/replicate.d.ts.map +0 -1
  378. package/lib/types/shared/claude-messages.d.ts.map +0 -1
  379. package/lib/types/shared/claude-thinking.d.ts.map +0 -1
  380. package/lib/types/test-driver/TestErrorCompletionStream.d.ts.map +0 -1
  381. package/lib/types/test-driver/TestValidationErrorCompletionStream.d.ts.map +0 -1
  382. package/lib/types/test-driver/index.d.ts.map +0 -1
  383. package/lib/types/test-driver/utils.d.ts.map +0 -1
  384. package/lib/types/togetherai/index.d.ts +0 -23
  385. package/lib/types/togetherai/index.d.ts.map +0 -1
  386. package/lib/types/togetherai/interfaces.d.ts.map +0 -1
  387. package/lib/types/vertexai/debug.d.ts +0 -2
  388. package/lib/types/vertexai/debug.d.ts.map +0 -1
  389. package/lib/types/vertexai/embeddings/embeddings-image.d.ts +0 -11
  390. package/lib/types/vertexai/embeddings/embeddings-image.d.ts.map +0 -1
  391. package/lib/types/vertexai/embeddings/embeddings-text.d.ts +0 -10
  392. package/lib/types/vertexai/embeddings/embeddings-text.d.ts.map +0 -1
  393. package/lib/types/vertexai/index.d.ts.map +0 -1
  394. package/lib/types/vertexai/models/claude.d.ts.map +0 -1
  395. package/lib/types/vertexai/models/gemini.d.ts.map +0 -1
  396. package/lib/types/vertexai/models/imagen.d.ts.map +0 -1
  397. package/lib/types/vertexai/models/llama.d.ts.map +0 -1
  398. package/lib/types/vertexai/models.d.ts +0 -20
  399. package/lib/types/vertexai/models.d.ts.map +0 -1
  400. package/lib/types/watsonx/index.d.ts.map +0 -1
  401. package/lib/types/watsonx/interfaces.d.ts.map +0 -1
  402. package/lib/types/xai/index.d.ts.map +0 -1
  403. package/src/vertexai/embeddings/embeddings-image.ts +0 -52
  404. package/src/vertexai/embeddings/embeddings-text.ts +0 -54
  405. /package/lib/{esm/bedrock → bedrock}/payloads.js +0 -0
  406. /package/lib/{esm/mistral → mistral}/types.js +0 -0
  407. /package/lib/{esm/togetherai → togetherai}/interfaces.js +0 -0
  408. /package/lib/{types/watsonx → watsonx}/interfaces.d.ts +0 -0
  409. /package/lib/{esm/watsonx → watsonx}/interfaces.js +0 -0
@@ -1,62 +1,92 @@
1
- import { FinishReason, FunctionCallingConfigMode, HarmBlockThreshold, HarmCategory, Modality, ProminentPeople, ThinkingLevel } from "@google/genai";
2
- import { getConversationMeta, getGeminiModelVersion, incrementConversationTurn, isGeminiModelVersionGte, LlumiverseError, ModelType, PromptRole, readStreamAsBase64, stripBase64ImagesFromConversation, stripHeartbeatsFromConversation, truncateLargeTextInConversation, unwrapConversationArray } from "@llumiverse/core";
3
- import { asyncMap } from "@llumiverse/core/async";
1
+ import { FinishReason, FunctionCallingConfigMode, HarmBlockThreshold, HarmCategory, Modality, ProminentPeople, ThinkingLevel, } from '@google/genai';
2
+ import { getConversationMeta, getGeminiModelVersion, incrementConversationTurn, isGeminiModelVersionGte, LlumiverseError, ModelType, PromptRole, readStreamAsBase64, stripBase64ImagesFromConversation, stripHeartbeatsFromConversation, truncateLargeTextInConversation, unwrapConversationArray, } from '@llumiverse/core';
3
+ import { asyncMap } from '@llumiverse/core/async';
4
+ import { truncateBinaryForDebug } from '../../shared/debug-prompt.js';
4
5
  function supportsStructuredOutput(options) {
5
6
  // Gemini 1.0 Ultra does not support JSON output, 1.0 Pro does.
6
- return !!options.result_schema && !options.model.includes("ultra");
7
+ return !!options.result_schema && !options.model.includes('ultra');
7
8
  }
8
9
  const geminiSafetySettings = [
9
10
  {
10
11
  category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
11
- threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH
12
+ threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH,
12
13
  },
13
14
  {
14
15
  category: HarmCategory.HARM_CATEGORY_HARASSMENT,
15
- threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH
16
+ threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH,
16
17
  },
17
18
  {
18
19
  category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
19
- threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH
20
+ threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH,
20
21
  },
21
22
  {
22
23
  category: HarmCategory.HARM_CATEGORY_HATE_SPEECH,
23
- threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH
24
+ threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH,
24
25
  },
25
26
  {
26
27
  category: HarmCategory.HARM_CATEGORY_UNSPECIFIED,
27
- threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH
28
+ threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH,
28
29
  },
29
30
  {
30
31
  category: HarmCategory.HARM_CATEGORY_CIVIC_INTEGRITY,
31
- threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH
32
- }
32
+ threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH,
33
+ },
33
34
  ];
35
+ function formatGeminiContentForDebug(content) {
36
+ return {
37
+ ...content,
38
+ parts: content.parts?.map((part) => {
39
+ if (!part.inlineData?.data) {
40
+ return part;
41
+ }
42
+ return {
43
+ ...part,
44
+ inlineData: {
45
+ ...part.inlineData,
46
+ data: truncateBinaryForDebug(part.inlineData.data),
47
+ },
48
+ };
49
+ }),
50
+ };
51
+ }
52
+ export function formatGeminiDebugPrompt(prompt) {
53
+ return {
54
+ ...prompt,
55
+ contents: prompt.contents.map(formatGeminiContentForDebug),
56
+ system: prompt.system ? formatGeminiContentForDebug(prompt.system) : undefined,
57
+ };
58
+ }
34
59
  // We do the mapping here rather than in common to avoid bringing the SDK into the common package.
35
60
  function getProminentPeopleOption(prominentPeople) {
36
61
  switch (prominentPeople) {
37
- case "ALLOW_PROMINENT_PEOPLE":
62
+ case 'ALLOW_PROMINENT_PEOPLE':
38
63
  return ProminentPeople.ALLOW_PROMINENT_PEOPLE;
39
- case "BLOCK_PROMINENT_PEOPLE":
64
+ case 'BLOCK_PROMINENT_PEOPLE':
40
65
  return ProminentPeople.BLOCK_PROMINENT_PEOPLE;
41
- case "PROMINENT_PEOPLE_UNSPECIFIED":
66
+ case 'PROMINENT_PEOPLE_UNSPECIFIED':
42
67
  return ProminentPeople.PROMINENT_PEOPLE_UNSPECIFIED;
43
68
  default:
44
69
  return undefined;
45
70
  }
46
71
  }
47
- function getGeminiPayload(options, prompt) {
72
+ export function getGeminiPayload(options, prompt) {
48
73
  const model_options = options.model_options;
49
74
  const tools = getToolDefinitions(options.tools);
50
75
  // When no tools are provided but conversation contains functionCall/functionResponse parts
51
76
  // (e.g. checkpoint summary calls), convert them to text to avoid API errors.
52
77
  // Use a local variable to avoid mutating the caller's conversation object.
53
- let payloadContents = prompt.contents;
78
+ let payloadContents = mergeConsecutiveRole(prompt.contents);
54
79
  if (!tools && payloadContents) {
55
- const hasToolParts = payloadContents.some(c => c.parts?.some(p => p.functionCall || p.functionResponse));
80
+ const hasToolParts = payloadContents.some((c) => c.parts?.some((p) => p.functionCall || p.functionResponse));
56
81
  if (hasToolParts) {
57
82
  payloadContents = convertGeminiFunctionPartsToText(payloadContents);
58
83
  }
59
84
  }
85
+ // Drop functionResponse parts whose functionCall was lost (e.g. compaction),
86
+ // which would otherwise trip Gemini's functionCall/functionResponse pairing.
87
+ if (payloadContents) {
88
+ payloadContents = fixOrphanedToolResults(payloadContents);
89
+ }
60
90
  const useStructuredOutput = supportsStructuredOutput(options) && !tools;
61
91
  const configNanoBanana = {
62
92
  systemInstruction: prompt.system,
@@ -77,20 +107,22 @@ function getGeminiPayload(options, prompt) {
77
107
  prominentPeople: getProminentPeopleOption(model_options?.prominent_people),
78
108
  outputMimeType: model_options?.output_mime_type,
79
109
  outputCompressionQuality: model_options?.output_compression_quality,
80
- }
110
+ },
81
111
  };
82
112
  const config = {
83
113
  systemInstruction: prompt.system,
84
114
  safetySettings: geminiSafetySettings,
85
115
  tools: tools ? [tools] : undefined,
86
- toolConfig: tools ? {
87
- functionCallingConfig: {
88
- mode: FunctionCallingConfigMode.AUTO,
116
+ toolConfig: tools
117
+ ? {
118
+ functionCallingConfig: {
119
+ mode: FunctionCallingConfigMode.AUTO,
120
+ },
89
121
  }
90
- } : undefined,
122
+ : undefined,
91
123
  candidateCount: 1,
92
124
  //JSON/Structured output
93
- responseMimeType: useStructuredOutput ? "application/json" : undefined,
125
+ responseMimeType: useStructuredOutput ? 'application/json' : undefined,
94
126
  responseJsonSchema: useStructuredOutput ? options.result_schema : undefined,
95
127
  //Model options
96
128
  temperature: model_options?.temperature,
@@ -107,7 +139,7 @@ function getGeminiPayload(options, prompt) {
107
139
  return {
108
140
  model: options.model,
109
141
  contents: payloadContents,
110
- config: options.model.toLowerCase().includes("image") ? configNanoBanana : config,
142
+ config: options.model.toLowerCase().includes('image') ? configNanoBanana : config,
111
143
  };
112
144
  }
113
145
  /**
@@ -121,17 +153,17 @@ function extractCompletionResults(content) {
121
153
  for (const part of parts) {
122
154
  if (part.text) {
123
155
  results.push({
124
- type: "text",
125
- value: part.text
156
+ type: 'text',
157
+ value: part.text,
126
158
  });
127
159
  }
128
160
  else if (part.inlineData) {
129
- const base64ImageBytes = part.inlineData.data ?? "";
130
- const mimeType = part.inlineData.mimeType ?? "image/png";
161
+ const base64ImageBytes = part.inlineData.data ?? '';
162
+ const mimeType = part.inlineData.mimeType ?? 'image/png';
131
163
  const imageUrl = `data:${mimeType};base64,${base64ImageBytes}`;
132
164
  results.push({
133
- type: "image",
134
- value: imageUrl
165
+ type: 'image',
166
+ value: imageUrl,
135
167
  });
136
168
  }
137
169
  }
@@ -182,6 +214,49 @@ export function mergeConsecutiveRole(contents) {
182
214
  result.push(currentContent);
183
215
  return result;
184
216
  }
217
+ /**
218
+ * Drop functionResponse parts whose name has no matching functionCall in the
219
+ * immediately-preceding `model` content. Gemini pairs a functionResponse to its
220
+ * functionCall by name; a response left dangling after its call was dropped
221
+ * (e.g. by conversation compaction/trimming, or an unmergeable parallel batch)
222
+ * causes the API to reject the request. Mirrors the same guard added to the
223
+ * Claude, Bedrock, and OpenAI drivers.
224
+ *
225
+ * Run after mergeConsecutiveRole so parallel responses that were split across
226
+ * user contents are first recombined under the model turn that issued the calls,
227
+ * and are therefore not mistaken for orphans.
228
+ */
229
+ export function fixOrphanedToolResults(contents) {
230
+ if (contents.length === 0)
231
+ return contents;
232
+ const result = [];
233
+ for (let i = 0; i < contents.length; i++) {
234
+ const content = contents[i];
235
+ if (content.role !== 'user' || !content.parts) {
236
+ result.push(content);
237
+ continue;
238
+ }
239
+ const hasFunctionResponse = content.parts.some((part) => part.functionResponse);
240
+ if (!hasFunctionResponse) {
241
+ result.push(content);
242
+ continue;
243
+ }
244
+ const prev = contents[i - 1];
245
+ const allowedNames = new Set();
246
+ if (prev && prev.role === 'model' && prev.parts) {
247
+ for (const part of prev.parts) {
248
+ if (part.functionCall?.name)
249
+ allowedNames.add(part.functionCall.name);
250
+ }
251
+ }
252
+ const filtered = content.parts.filter((part) => part.functionResponse ? allowedNames.has(part.functionResponse.name ?? '') : true);
253
+ // Drop the content if every part was an orphaned functionResponse.
254
+ if (filtered.length === 0)
255
+ continue;
256
+ result.push(filtered.length === content.parts.length ? content : { ...content, parts: filtered });
257
+ }
258
+ return result;
259
+ }
185
260
  const supportedFinishReasons = [
186
261
  FinishReason.MAX_TOKENS,
187
262
  FinishReason.STOP,
@@ -205,7 +280,7 @@ function geminiThinkingBudget(option) {
205
280
  // Set minimum thinking level by default.
206
281
  // Docs: https://ai.google.dev/gemini-api/docs/thinking#set-budget
207
282
  if (getGeminiModelVersion(option.model) === '2.5') {
208
- if (option.model.includes("pro")) {
283
+ if (option.model.includes('pro')) {
209
284
  return 128;
210
285
  }
211
286
  return 0;
@@ -213,28 +288,28 @@ function geminiThinkingBudget(option) {
213
288
  return undefined;
214
289
  }
215
290
  function geminiThinkingLevelForEffort(model, effort) {
216
- if (model.includes("gemini-3-pro-image")) {
291
+ if (model.includes('gemini-3-pro-image')) {
217
292
  return ThinkingLevel.HIGH;
218
293
  }
219
- if (model.includes("gemini-3.1-flash-image")) {
220
- return effort === "low" ? ThinkingLevel.MINIMAL : ThinkingLevel.HIGH;
294
+ if (model.includes('gemini-3.1-flash-image')) {
295
+ return effort === 'low' ? ThinkingLevel.MINIMAL : ThinkingLevel.HIGH;
221
296
  }
222
297
  switch (effort) {
223
- case "low":
298
+ case 'low':
224
299
  return ThinkingLevel.LOW;
225
- case "medium":
300
+ case 'medium':
226
301
  return ThinkingLevel.MEDIUM;
227
- case "high":
302
+ case 'high':
228
303
  return ThinkingLevel.HIGH;
229
304
  default:
230
305
  return undefined;
231
306
  }
232
307
  }
233
308
  function geminiBudgetForEffort(model, effort) {
234
- const isFlashLite = model.includes("flash-lite");
235
- const isFlash = model.includes("flash") && !isFlashLite;
236
- const isPro = model.includes("pro");
237
- if (effort === "low") {
309
+ const isFlashLite = model.includes('flash-lite');
310
+ const isFlash = model.includes('flash') && !isFlashLite;
311
+ const isPro = model.includes('pro');
312
+ if (effort === 'low') {
238
313
  if (isPro)
239
314
  return 128;
240
315
  if (isFlashLite)
@@ -243,7 +318,7 @@ function geminiBudgetForEffort(model, effort) {
243
318
  return 1;
244
319
  return 1024;
245
320
  }
246
- if (effort === "medium") {
321
+ if (effort === 'medium') {
247
322
  return 8192;
248
323
  }
249
324
  if (isPro)
@@ -281,14 +356,14 @@ function geminiThinkingConfig(option) {
281
356
  if (isGeminiModelVersionGte(option.model, '3.0')) {
282
357
  return {
283
358
  includeThoughts: include_thoughts,
284
- thinkingLevel: option.model.includes("gemini-3-pro-image") ? ThinkingLevel.HIGH : ThinkingLevel.LOW
359
+ thinkingLevel: option.model.includes('gemini-3-pro-image') ? ThinkingLevel.HIGH : ThinkingLevel.LOW,
285
360
  };
286
361
  }
287
362
  if (isGeminiModelVersionGte(option.model, '2.5')) {
288
363
  const thinking_budget_tokens = geminiThinkingBudget(option) ?? 0;
289
364
  return {
290
365
  includeThoughts: include_thoughts,
291
- thinkingBudget: thinking_budget_tokens
366
+ thinkingBudget: thinking_budget_tokens,
292
367
  };
293
368
  }
294
369
  }
@@ -300,33 +375,33 @@ export class GeminiModelDefinition {
300
375
  name: modelId,
301
376
  provider: 'vertexai',
302
377
  type: ModelType.Text,
303
- can_stream: true
378
+ can_stream: true,
304
379
  };
305
380
  }
306
381
  async createPrompt(_driver, segments, options) {
307
- const splits = options.model.split("/");
382
+ const splits = options.model.split('/');
308
383
  const modelName = splits[splits.length - 1];
309
384
  options = { ...options, model: modelName };
310
385
  const schema = options.result_schema;
311
386
  let contents = [];
312
- let system = { role: "user", parts: [] }; // Single content block for system messages
387
+ let system = { role: 'user', parts: [] }; // Single content block for system messages
313
388
  const safety = [];
314
389
  for (const msg of segments) {
315
390
  // Role specific handling
316
391
  if (msg.role === PromptRole.system) {
317
392
  // Text only for system messages
318
393
  if (msg.files && msg.files.length > 0) {
319
- throw new Error("Gemini does not support files/images etc. in system messages. Only text content is allowed.");
394
+ throw new Error('Gemini does not support files/images etc. in system messages. Only text content is allowed.');
320
395
  }
321
396
  if (msg.content) {
322
397
  system.parts?.push({
323
- text: msg.content
398
+ text: msg.content,
324
399
  });
325
400
  }
326
401
  }
327
402
  else if (msg.role === PromptRole.tool) {
328
403
  if (!msg.tool_use_id) {
329
- throw new Error("Tool response missing tool_use_id");
404
+ throw new Error('Tool response missing tool_use_id');
330
405
  }
331
406
  // Build functionResponse part with optional thought_signature for Gemini thinking models
332
407
  const functionResponsePart = {
@@ -339,10 +414,11 @@ export class GeminiModelDefinition {
339
414
  };
340
415
  contents.push({
341
416
  role: 'user',
342
- parts: [functionResponsePart]
417
+ parts: [functionResponsePart],
343
418
  });
344
419
  }
345
- else { // PromptRole.user, PromptRole.assistant, PromptRole.safety
420
+ else {
421
+ // PromptRole.user, PromptRole.assistant, PromptRole.safety
346
422
  const parts = [];
347
423
  // Text content handling
348
424
  if (msg.content) {
@@ -353,14 +429,14 @@ export class GeminiModelDefinition {
353
429
  // File content handling
354
430
  if (msg.files) {
355
431
  for (const f of msg.files) {
356
- const fileUrl = await f.getURL();
357
- const isGsUrl = fileUrl.startsWith('gs://') || fileUrl.startsWith('https://storage.googleapis.com/');
358
- if (isGsUrl) {
432
+ const fileUri = await f.getURI();
433
+ const isGsUri = fileUri.startsWith('gs://') || fileUri.startsWith('https://storage.googleapis.com/');
434
+ if (isGsUri) {
359
435
  parts.push({
360
436
  fileData: {
361
- fileUri: fileUrl,
362
- mimeType: f.mime_type
363
- }
437
+ fileUri,
438
+ mimeType: f.mime_type,
439
+ },
364
440
  });
365
441
  }
366
442
  else {
@@ -370,8 +446,8 @@ export class GeminiModelDefinition {
370
446
  parts.push({
371
447
  inlineData: {
372
448
  data,
373
- mimeType: f.mime_type
374
- }
449
+ mimeType: f.mime_type,
450
+ },
375
451
  });
376
452
  }
377
453
  }
@@ -397,17 +473,19 @@ export class GeminiModelDefinition {
397
473
  if (supportsStructuredOutput(options) && !options.tools) {
398
474
  // Gemini structured output is unnecessarily sparse. Adding encouragement to fill the fields.
399
475
  // Putting JSON in prompt is not recommended by Google, when using structured output.
400
- system.parts?.push({ text: "Fill all appropriate fields in the JSON output." });
476
+ system.parts?.push({ text: 'Fill all appropriate fields in the JSON output.' });
401
477
  }
402
478
  else {
403
479
  // Fallback to putting the schema in the system instructions, if not using structured output.
404
480
  if (options.tools) {
405
481
  system.parts?.push({
406
- text: "When not calling tools, the output must be a JSON object using the following JSON Schema:\n" + JSON.stringify(schema)
482
+ text: `When not calling tools, the output must be a JSON object using the following JSON Schema:\n${JSON.stringify(schema)}`,
407
483
  });
408
484
  }
409
485
  else {
410
- system.parts?.push({ text: "The output must be a JSON object using the following JSON Schema:\n" + JSON.stringify(schema) });
486
+ system.parts?.push({
487
+ text: `The output must be a JSON object using the following JSON Schema:\n${JSON.stringify(schema)}`,
488
+ });
411
489
  }
412
490
  }
413
491
  }
@@ -424,7 +502,7 @@ export class GeminiModelDefinition {
424
502
  return { contents, system };
425
503
  }
426
504
  usageMetadataToTokenUsage(driver, usageMetadata) {
427
- if (!usageMetadata || !usageMetadata.totalTokenCount) {
505
+ if (!usageMetadata?.totalTokenCount) {
428
506
  return {};
429
507
  }
430
508
  const tokenUsage = {
@@ -434,15 +512,16 @@ export class GeminiModelDefinition {
434
512
  prompt_new: (usageMetadata.promptTokenCount ?? 0) - (usageMetadata.cachedContentTokenCount ?? 0),
435
513
  };
436
514
  //Output/Response side
437
- tokenUsage.result = (usageMetadata.candidatesTokenCount ?? 0)
438
- + (usageMetadata.thoughtsTokenCount ?? 0)
439
- + (usageMetadata.toolUsePromptTokenCount ?? 0);
515
+ tokenUsage.result =
516
+ (usageMetadata.candidatesTokenCount ?? 0) +
517
+ (usageMetadata.thoughtsTokenCount ?? 0) +
518
+ (usageMetadata.toolUsePromptTokenCount ?? 0);
440
519
  if ((tokenUsage.total ?? 0) !== (tokenUsage.prompt ?? 0) + tokenUsage.result) {
441
520
  // Token-accounting mismatch: warn-level diagnostic (the call still
442
521
  // returns the best-effort tokenUsage). Use the driver's structured
443
522
  // logger so we don't promote stderr writes to ERROR in serverless
444
523
  // log aggregators — see the recoverable-tool-call sites below.
445
- driver.logger.warn({ total: tokenUsage.total, prompt: tokenUsage.prompt, result: tokenUsage.result }, "[VertexAI] Gemini token usage mismatch: total does not equal prompt + result");
524
+ driver.logger.warn({ total: tokenUsage.total, prompt: tokenUsage.prompt, result: tokenUsage.result }, '[VertexAI] Gemini token usage mismatch: total does not equal prompt + result');
446
525
  }
447
526
  if (!tokenUsage.result) {
448
527
  tokenUsage.result = undefined; // If no result, mark as undefined
@@ -450,9 +529,9 @@ export class GeminiModelDefinition {
450
529
  return tokenUsage;
451
530
  }
452
531
  async requestTextCompletion(driver, prompt, options) {
453
- const splits = options.model.split("/");
454
- let region = undefined;
455
- if (splits[0] === "locations" && splits.length >= 2) {
532
+ const splits = options.model.split('/');
533
+ let region;
534
+ if (splits[0] === 'locations' && splits.length >= 2) {
456
535
  region = splits[1];
457
536
  }
458
537
  const modelName = splits[splits.length - 1];
@@ -468,34 +547,37 @@ export class GeminiModelDefinition {
468
547
  let conversation = updateConversation(options.conversation, prompt.contents);
469
548
  prompt.contents = conversation;
470
549
  // TODO: Remove hack, use global endpoint manually if needed.
471
- if (options.model.includes("gemini-2.5-flash-image")) {
472
- region = "global"; // Gemini Flash Image only available in global region, this is for nano-banana model
550
+ if (options.model.includes('gemini-2.5-flash-image')) {
551
+ region = 'global'; // Gemini Flash Image only available in global region, this is for nano-banana model
473
552
  }
474
553
  const model_options = options.model_options;
475
- const client = driver.getGoogleGenAIClient(region, model_options?.flex ?? false);
554
+ const client = driver.getGoogleGenAIClient(region, model_options?.flex ?? false, options.httpTimeout);
476
555
  const payload = getGeminiPayload(options, prompt);
477
556
  const response = await client.models.generateContent(payload);
478
557
  const token_usage = this.usageMetadataToTokenUsage(driver, response.usageMetadata);
479
558
  let tool_use;
480
559
  let finish_reason, result;
481
- const candidate = response.candidates && response.candidates[0];
560
+ const candidate = response.candidates?.[0];
482
561
  if (candidate) {
483
562
  switch (candidate.finishReason) {
484
563
  case FinishReason.MAX_TOKENS:
485
- finish_reason = "length";
564
+ finish_reason = 'length';
486
565
  break;
487
566
  case FinishReason.STOP:
488
- finish_reason = "stop";
567
+ finish_reason = 'stop';
489
568
  break;
490
- default: finish_reason = candidate.finishReason;
569
+ default:
570
+ finish_reason = candidate.finishReason;
491
571
  }
492
572
  const content = candidate.content;
493
573
  // Check for unsupported finish reasons, but allow recoverable tool call issues
494
574
  const isRecoverableToolCall = recoverableToolCallReasons.includes(candidate.finishReason);
495
- if (candidate.finishReason && !supportedFinishReasons.includes(candidate.finishReason) && !isRecoverableToolCall) {
496
- throw new Error(`Unsupported finish reason: ${candidate.finishReason}, `
497
- + `finish message: ${candidate.finishMessage}, `
498
- + `content: ${JSON.stringify(content, null, 2)}, safety: ${JSON.stringify(candidate.safetyRatings, null, 2)}`);
575
+ if (candidate.finishReason &&
576
+ !supportedFinishReasons.includes(candidate.finishReason) &&
577
+ !isRecoverableToolCall) {
578
+ throw new Error(`Unsupported finish reason: ${candidate.finishReason}, ` +
579
+ `finish message: ${candidate.finishMessage}, ` +
580
+ `content: ${JSON.stringify(content, null, 2)}, safety: ${JSON.stringify(candidate.safetyRatings, null, 2)}`);
499
581
  }
500
582
  if (content) {
501
583
  tool_use = collectToolUseParts(content);
@@ -506,14 +588,14 @@ export class GeminiModelDefinition {
506
588
  // to ERROR severity for what is, by definition, a recoverable event.
507
589
  if (isRecoverableToolCall && tool_use && tool_use.length > 0) {
508
590
  driver.logger.warn(`[Gemini] Recoverable tool call issue (${candidate.finishReason}): ` +
509
- `Model tried to call undeclared tool(s): ${tool_use.map(t => t.tool_name).join(', ')}`);
591
+ `Model tried to call undeclared tool(s): ${tool_use.map((t) => t.tool_name).join(', ')}`);
510
592
  }
511
593
  result = extractCompletionResults(content);
512
594
  conversation = updateConversation(conversation, [content]);
513
595
  }
514
596
  }
515
597
  if (tool_use) {
516
- finish_reason = "tool_use";
598
+ finish_reason = 'tool_use';
517
599
  }
518
600
  // Increment turn counter for deferred stripping
519
601
  conversation = incrementConversationTurn(conversation);
@@ -522,7 +604,7 @@ export class GeminiModelDefinition {
522
604
  const stripOptions = {
523
605
  keepForTurns: options.stripImagesAfterTurns ?? Infinity,
524
606
  currentTurn,
525
- textMaxTokens: options.stripTextMaxTokens
607
+ textMaxTokens: options.stripTextMaxTokens,
526
608
  };
527
609
  let processedConversation = stripBase64ImagesFromConversation(conversation, stripOptions);
528
610
  // Truncate large text content if configured
@@ -535,18 +617,18 @@ export class GeminiModelDefinition {
535
617
  // Preserve system instruction in conversation for multi-turn support
536
618
  const finalConversation = storeSystemInConversation(processedConversation, prompt.system);
537
619
  return {
538
- result: result && result.length > 0 ? result : [{ type: "text", value: '' }],
620
+ result: result && result.length > 0 ? result : [{ type: 'text', value: '' }],
539
621
  token_usage: token_usage,
540
622
  finish_reason: finish_reason,
541
623
  original_response: options.include_original_response ? response : undefined,
542
624
  conversation: finalConversation,
543
- tool_use
625
+ tool_use,
544
626
  };
545
627
  }
546
628
  async requestTextCompletionStream(driver, prompt, options) {
547
- const splits = options.model.split("/");
548
- let region = undefined;
549
- if (splits[0] === "locations" && splits.length >= 2) {
629
+ const splits = options.model.split('/');
630
+ let region;
631
+ if (splits[0] === 'locations' && splits.length >= 2) {
550
632
  region = splits[1];
551
633
  }
552
634
  const modelName = splits[splits.length - 1];
@@ -562,11 +644,11 @@ export class GeminiModelDefinition {
562
644
  // Include conversation history in prompt contents (same as non-streaming)
563
645
  const conversation = updateConversation(options.conversation, prompt.contents);
564
646
  prompt.contents = conversation;
565
- if (options.model.includes("gemini-2.5-flash-image")) {
566
- region = "global"; // Gemini Flash Image only available in global region, this is for nano-banana model
647
+ if (options.model.includes('gemini-2.5-flash-image')) {
648
+ region = 'global'; // Gemini Flash Image only available in global region, this is for nano-banana model
567
649
  }
568
650
  const model_options = options.model_options;
569
- const client = driver.getGoogleGenAIClient(region, model_options?.flex ?? false);
651
+ const client = driver.getGoogleGenAIClient(region, model_options?.flex ?? false, options.httpTimeout);
570
652
  const payload = getGeminiPayload(options, prompt);
571
653
  const response = await client.models.generateContentStream(payload);
572
654
  const stream = asyncMap(response, async (item) => {
@@ -577,33 +659,36 @@ export class GeminiModelDefinition {
577
659
  let finish_reason;
578
660
  switch (candidate.finishReason) {
579
661
  case FinishReason.MAX_TOKENS:
580
- finish_reason = "length";
662
+ finish_reason = 'length';
581
663
  break;
582
664
  case FinishReason.STOP:
583
- finish_reason = "stop";
665
+ finish_reason = 'stop';
584
666
  break;
585
- default: finish_reason = candidate.finishReason;
667
+ default:
668
+ finish_reason = candidate.finishReason;
586
669
  }
587
670
  // Check for unsupported finish reasons, but allow recoverable tool call issues
588
671
  const isRecoverableToolCall = recoverableToolCallReasons.includes(candidate.finishReason);
589
- if (candidate.finishReason && !supportedFinishReasons.includes(candidate.finishReason) && !isRecoverableToolCall) {
590
- throw new Error(`Unsupported finish reason: ${candidate.finishReason}, `
591
- + `finish message: ${candidate.finishMessage}, `
592
- + `content: ${JSON.stringify(candidate.content, null, 2)}, safety: ${JSON.stringify(candidate.safetyRatings, null, 2)}`);
672
+ if (candidate.finishReason &&
673
+ !supportedFinishReasons.includes(candidate.finishReason) &&
674
+ !isRecoverableToolCall) {
675
+ throw new Error(`Unsupported finish reason: ${candidate.finishReason}, ` +
676
+ `finish message: ${candidate.finishMessage}, ` +
677
+ `content: ${JSON.stringify(candidate.content, null, 2)}, safety: ${JSON.stringify(candidate.safetyRatings, null, 2)}`);
593
678
  }
594
679
  if (candidate.content?.role === 'model') {
595
680
  // Collect all parts in order (text and images)
596
681
  const combinedResults = extractCompletionResults(candidate.content);
597
682
  tool_use = collectToolUseParts(candidate.content);
598
683
  if (tool_use) {
599
- finish_reason = "tool_use";
684
+ finish_reason = 'tool_use';
600
685
  // Log warning for recoverable tool call issues — see the
601
686
  // matching site in `requestTextCompletion` above for why
602
687
  // we route through the driver's logger instead of
603
688
  // `console.warn`.
604
689
  if (isRecoverableToolCall) {
605
690
  driver.logger.warn(`[Gemini] Recoverable tool call issue (${candidate.finishReason}): ` +
606
- `Model tried to call undeclared tool(s): ${tool_use.map(t => t.tool_name).join(', ')}`);
691
+ `Model tried to call undeclared tool(s): ${tool_use.map((t) => t.tool_name).join(', ')}`);
607
692
  }
608
693
  }
609
694
  return {
@@ -617,8 +702,10 @@ export class GeminiModelDefinition {
617
702
  }
618
703
  //No normal output, returning block reason if it exists.
619
704
  return {
620
- result: item.promptFeedback?.blockReasonMessage ? [{ type: "text", value: item.promptFeedback.blockReasonMessage }] : [],
621
- finish_reason: item.promptFeedback?.blockReason ?? "",
705
+ result: item.promptFeedback?.blockReasonMessage
706
+ ? [{ type: 'text', value: item.promptFeedback.blockReasonMessage }]
707
+ : [],
708
+ finish_reason: item.promptFeedback?.blockReason ?? '',
622
709
  token_usage: token_usage,
623
710
  };
624
711
  });
@@ -655,7 +742,7 @@ export class GeminiModelDefinition {
655
742
  const apiError = error;
656
743
  const httpStatusCode = apiError.status;
657
744
  // Extract error message
658
- const message = apiError.message || String(error);
745
+ const message = apiError.message;
659
746
  // Build user-facing message with status code
660
747
  let userMessage = message;
661
748
  // Include status code in message (for end-user visibility)
@@ -663,7 +750,7 @@ export class GeminiModelDefinition {
663
750
  userMessage = `[${httpStatusCode}] ${userMessage}`;
664
751
  }
665
752
  // Determine retryability based on Google error codes
666
- const retryable = this.isGeminiErrorRetryable(httpStatusCode);
753
+ const retryable = this.isGeminiErrorRetryable(httpStatusCode, message);
667
754
  // Extract error name/type from message if present
668
755
  const errorName = this.extractErrorName(message);
669
756
  return new LlumiverseError(`[${context.provider}] ${userMessage}`, retryable, context, error, httpStatusCode, errorName);
@@ -676,13 +763,15 @@ export class GeminiModelDefinition {
676
763
  typeof error === 'object' &&
677
764
  'status' in error &&
678
765
  typeof error.status === 'number' &&
679
- 'message' in error);
766
+ 'message' in error &&
767
+ typeof error.message === 'string');
680
768
  }
681
769
  /**
682
770
  * Determine if a Google API error is retryable based on HTTP status code.
683
771
  *
684
772
  * Retryable errors (per Google AIP-194):
685
773
  * - 408 (REQUEST_TIMEOUT): Request timeout
774
+ * - 499 (CANCELLED / Client Closed Request): Transport cancellation
686
775
  * - 429 (RESOURCE_EXHAUSTED): Rate limit exceeded, quota exhausted
687
776
  * - 500 (INTERNAL): Internal server error
688
777
  * - 502 (BAD_GATEWAY): Bad gateway
@@ -697,15 +786,26 @@ export class GeminiModelDefinition {
697
786
  * - 409 (CONFLICT): Resource conflict
698
787
  * - Other 4xx client errors
699
788
  *
789
+ * Exception: certain 400s from Vertex AI's inline URL fetcher (used when
790
+ * passing a file by URL to multimodal models) surface as INVALID_ARGUMENT
791
+ * but are actually transient throttling/rate-limit signals on the
792
+ * fetcher, not a bad request. Detect those by message substring and
793
+ * treat them as retryable.
794
+ *
700
795
  * @param httpStatusCode - The HTTP status code from the API error
796
+ * @param message - The error message (used to detect transient 400 sub-cases)
701
797
  * @returns True if retryable, false if not retryable, undefined if unknown
702
798
  */
703
- isGeminiErrorRetryable(httpStatusCode) {
799
+ isGeminiErrorRetryable(httpStatusCode, message) {
800
+ if (message && this.isNonRetryableAuthError(message))
801
+ return false;
704
802
  // Retryable status codes
705
803
  if (httpStatusCode === 408)
706
804
  return true; // Request timeout
707
805
  if (httpStatusCode === 429)
708
806
  return true; // Rate limit/quota
807
+ if (httpStatusCode === 499)
808
+ return true; // Client closed / operation cancelled
709
809
  if (httpStatusCode === 502)
710
810
  return true; // Bad gateway
711
811
  if (httpStatusCode === 503)
@@ -714,12 +814,32 @@ export class GeminiModelDefinition {
714
814
  return true; // Gateway timeout
715
815
  if (httpStatusCode >= 500 && httpStatusCode < 600)
716
816
  return true; // Other 5xx server errors
817
+ // Vertex AI URL fetcher transient throttling, surfaced as 400 INVALID_ARGUMENT
818
+ // but really a Google-side rate limit on the inline-content fetcher.
819
+ if (httpStatusCode === 400 && message) {
820
+ if (message.includes('URL_REJECTED-REJECTED_CLIENT_THROTTLED') ||
821
+ message.includes('URL_REJECTED-REJECTED_RATE_LIMITED')) {
822
+ return true;
823
+ }
824
+ }
825
+ // A transport-level abort/cancel (request-timeout / dropped connection, sometimes reported
826
+ // as 499 client-closed) or a deadline-exceeded is transient and should be retried,
827
+ // even though it carries a 4xx status. Honor it before the 4xx -> non-retryable rule.
828
+ if (message) {
829
+ const lower = message.toLowerCase();
830
+ if (lower.includes('aborted') || lower.includes('cancelled') || lower.includes('deadline'))
831
+ return true;
832
+ }
717
833
  // Non-retryable 4xx client errors
718
834
  if (httpStatusCode >= 400 && httpStatusCode < 500)
719
835
  return false;
720
836
  // Unknown status codes - let consumer decide retry strategy
721
837
  return undefined;
722
838
  }
839
+ isNonRetryableAuthError(message) {
840
+ const lowerMessage = message.toLowerCase();
841
+ return lowerMessage.includes('invalid_grant') || lowerMessage.includes("credential's issuer");
842
+ }
723
843
  /**
724
844
  * Extract error type name from error message.
725
845
  * Google errors often include the error type in the message.
@@ -728,6 +848,7 @@ export class GeminiModelDefinition {
728
848
  extractErrorName(message) {
729
849
  // Common Google error patterns
730
850
  const patterns = [
851
+ /^Error code ([a-zA-Z0-9_-]+):/, // "Error code invalid_grant: message"
731
852
  /^([A-Z_]+):/, // "ERROR_NAME: message"
732
853
  /\[([A-Z_]+)\]/, // "[ERROR_NAME] message"
733
854
  /^(\w+Error):/, // "ErrorTypeError: message"
@@ -747,22 +868,23 @@ export class GeminiModelDefinition {
747
868
  * tools/toolConfig to be defined in the API request.
748
869
  */
749
870
  export function convertGeminiFunctionPartsToText(contents) {
750
- return contents.map(content => {
871
+ return contents.map((content) => {
751
872
  if (!content.parts)
752
873
  return content;
753
- const hasFunctionParts = content.parts.some(p => p.functionCall || p.functionResponse);
874
+ const hasFunctionParts = content.parts.some((p) => p.functionCall || p.functionResponse);
754
875
  if (!hasFunctionParts)
755
876
  return content;
756
- const newParts = content.parts.map(part => {
877
+ const newParts = content.parts.map((part) => {
757
878
  if (part.functionCall) {
758
879
  const argsStr = part.functionCall.args ? JSON.stringify(part.functionCall.args) : '';
759
- const truncated = argsStr.length > 500 ? argsStr.substring(0, 500) + '...' : argsStr;
880
+ const truncated = argsStr.length > 500 ? `${argsStr.substring(0, 500)}...` : argsStr;
760
881
  return { text: `[Tool call: ${part.functionCall.name}(${truncated})]` };
761
882
  }
762
883
  if (part.functionResponse) {
763
884
  const respStr = part.functionResponse.response
764
- ? JSON.stringify(part.functionResponse.response) : 'No response';
765
- const truncated = respStr.length > 500 ? respStr.substring(0, 500) + '...' : respStr;
885
+ ? JSON.stringify(part.functionResponse.response)
886
+ : 'No response';
887
+ const truncated = respStr.length > 500 ? `${respStr.substring(0, 500)}...` : respStr;
766
888
  return { text: `[Tool result for ${part.functionResponse.name}: ${truncated}]` };
767
889
  }
768
890
  return part;
@@ -843,11 +965,11 @@ function storeSystemInConversation(conversation, system) {
843
965
  */
844
966
  function formatFunctionResponse(response) {
845
967
  response = response.trim();
846
- if (response.startsWith("{") && response.endsWith("}")) {
968
+ if (response.startsWith('{') && response.endsWith('}')) {
847
969
  try {
848
970
  return JSON.parse(response);
849
971
  }
850
- catch (e) {
972
+ catch {
851
973
  return { output: response };
852
974
  }
853
975
  }