@llumiverse/drivers 1.2.0 → 1.4.0-dev.20260629.090753Z

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 (403) 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/anthropic/index.d.ts +23 -0
  6. package/lib/anthropic/index.d.ts.map +1 -0
  7. package/lib/anthropic/index.js +68 -0
  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 +17 -5
  68. package/lib/openai/index.d.ts.map +1 -0
  69. package/lib/{esm/openai → openai}/index.js +254 -148
  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/shared/claude-messages.d.ts +99 -0
  88. package/lib/shared/claude-messages.d.ts.map +1 -0
  89. package/lib/shared/claude-messages.js +869 -0
  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/vertexai/models/claude.d.ts +16 -0
  143. package/lib/vertexai/models/claude.d.ts.map +1 -0
  144. package/lib/vertexai/models/claude.js +65 -0
  145. package/lib/vertexai/models/claude.js.map +1 -0
  146. package/lib/{types/vertexai → vertexai}/models/gemini.d.ts +29 -5
  147. package/lib/vertexai/models/gemini.d.ts.map +1 -0
  148. package/lib/{esm/vertexai → vertexai}/models/gemini.js +255 -127
  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 +88 -36
  173. package/src/adobe/firefly.ts +60 -43
  174. package/src/anthropic/index.ts +121 -0
  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 -15
  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 +389 -254
  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 +1085 -0
  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 +339 -253
  219. package/src/vertexai/models/claude-error-handling.test.ts +86 -39
  220. package/src/vertexai/models/claude-streaming-spacing.test.ts +82 -75
  221. package/src/vertexai/models/claude.ts +84 -1041
  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 +372 -182
  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/azure/azure_foundry.js +0 -432
  235. package/lib/cjs/azure/azure_foundry.js.map +0 -1
  236. package/lib/cjs/bedrock/converse.js +0 -359
  237. package/lib/cjs/bedrock/converse.js.map +0 -1
  238. package/lib/cjs/bedrock/index.js +0 -1508
  239. package/lib/cjs/bedrock/index.js.map +0 -1
  240. package/lib/cjs/bedrock/nova-image-payload.js +0 -207
  241. package/lib/cjs/bedrock/nova-image-payload.js.map +0 -1
  242. package/lib/cjs/bedrock/payloads.js +0 -3
  243. package/lib/cjs/bedrock/s3.js +0 -107
  244. package/lib/cjs/bedrock/s3.js.map +0 -1
  245. package/lib/cjs/bedrock/twelvelabs.js +0 -87
  246. package/lib/cjs/bedrock/twelvelabs.js.map +0 -1
  247. package/lib/cjs/groq/index.js +0 -328
  248. package/lib/cjs/groq/index.js.map +0 -1
  249. package/lib/cjs/huggingface_ie.js +0 -201
  250. package/lib/cjs/huggingface_ie.js.map +0 -1
  251. package/lib/cjs/index.js +0 -31
  252. package/lib/cjs/index.js.map +0 -1
  253. package/lib/cjs/mistral/index.js +0 -176
  254. package/lib/cjs/mistral/index.js.map +0 -1
  255. package/lib/cjs/mistral/types.js +0 -83
  256. package/lib/cjs/mistral/types.js.map +0 -1
  257. package/lib/cjs/openai/azure_openai.js +0 -72
  258. package/lib/cjs/openai/azure_openai.js.map +0 -1
  259. package/lib/cjs/openai/index.js +0 -1129
  260. package/lib/cjs/openai/index.js.map +0 -1
  261. package/lib/cjs/openai/openai.js +0 -21
  262. package/lib/cjs/openai/openai.js.map +0 -1
  263. package/lib/cjs/openai/openai_compatible.js +0 -63
  264. package/lib/cjs/openai/openai_compatible.js.map +0 -1
  265. package/lib/cjs/openai/openai_format.js +0 -131
  266. package/lib/cjs/openai/openai_format.js.map +0 -1
  267. package/lib/cjs/package.json +0 -3
  268. package/lib/cjs/replicate.js +0 -275
  269. package/lib/cjs/replicate.js.map +0 -1
  270. package/lib/cjs/shared/claude-thinking.js +0 -60
  271. package/lib/cjs/shared/claude-thinking.js.map +0 -1
  272. package/lib/cjs/test-driver/TestErrorCompletionStream.js +0 -20
  273. package/lib/cjs/test-driver/TestErrorCompletionStream.js.map +0 -1
  274. package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js +0 -24
  275. package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js.map +0 -1
  276. package/lib/cjs/test-driver/index.js +0 -109
  277. package/lib/cjs/test-driver/index.js.map +0 -1
  278. package/lib/cjs/test-driver/utils.js +0 -30
  279. package/lib/cjs/test-driver/utils.js.map +0 -1
  280. package/lib/cjs/togetherai/index.js +0 -126
  281. package/lib/cjs/togetherai/index.js.map +0 -1
  282. package/lib/cjs/togetherai/interfaces.js +0 -3
  283. package/lib/cjs/togetherai/interfaces.js.map +0 -1
  284. package/lib/cjs/vertexai/debug.js +0 -12
  285. package/lib/cjs/vertexai/debug.js.map +0 -1
  286. package/lib/cjs/vertexai/embeddings/embeddings-image.js +0 -27
  287. package/lib/cjs/vertexai/embeddings/embeddings-image.js.map +0 -1
  288. package/lib/cjs/vertexai/embeddings/embeddings-text.js +0 -23
  289. package/lib/cjs/vertexai/embeddings/embeddings-text.js.map +0 -1
  290. package/lib/cjs/vertexai/index.js +0 -644
  291. package/lib/cjs/vertexai/index.js.map +0 -1
  292. package/lib/cjs/vertexai/models/claude.js +0 -917
  293. package/lib/cjs/vertexai/models/claude.js.map +0 -1
  294. package/lib/cjs/vertexai/models/gemini.js +0 -858
  295. package/lib/cjs/vertexai/models/gemini.js.map +0 -1
  296. package/lib/cjs/vertexai/models/imagen.js +0 -303
  297. package/lib/cjs/vertexai/models/imagen.js.map +0 -1
  298. package/lib/cjs/vertexai/models/llama.js +0 -183
  299. package/lib/cjs/vertexai/models/llama.js.map +0 -1
  300. package/lib/cjs/vertexai/models.js +0 -35
  301. package/lib/cjs/vertexai/models.js.map +0 -1
  302. package/lib/cjs/watsonx/index.js +0 -161
  303. package/lib/cjs/watsonx/index.js.map +0 -1
  304. package/lib/cjs/watsonx/interfaces.js +0 -3
  305. package/lib/cjs/xai/index.js +0 -65
  306. package/lib/cjs/xai/index.js.map +0 -1
  307. package/lib/esm/adobe/firefly.js +0 -116
  308. package/lib/esm/adobe/firefly.js.map +0 -1
  309. package/lib/esm/azure/azure_foundry.js.map +0 -1
  310. package/lib/esm/bedrock/converse.js.map +0 -1
  311. package/lib/esm/bedrock/index.js.map +0 -1
  312. package/lib/esm/bedrock/nova-image-payload.js.map +0 -1
  313. package/lib/esm/bedrock/payloads.js.map +0 -1
  314. package/lib/esm/bedrock/s3.js.map +0 -1
  315. package/lib/esm/bedrock/twelvelabs.js.map +0 -1
  316. package/lib/esm/groq/index.js.map +0 -1
  317. package/lib/esm/huggingface_ie.js.map +0 -1
  318. package/lib/esm/index.js +0 -15
  319. package/lib/esm/index.js.map +0 -1
  320. package/lib/esm/mistral/index.js.map +0 -1
  321. package/lib/esm/mistral/types.js.map +0 -1
  322. package/lib/esm/openai/azure_openai.js.map +0 -1
  323. package/lib/esm/openai/index.js.map +0 -1
  324. package/lib/esm/openai/openai.js +0 -14
  325. package/lib/esm/openai/openai.js.map +0 -1
  326. package/lib/esm/openai/openai_compatible.js.map +0 -1
  327. package/lib/esm/openai/openai_format.js.map +0 -1
  328. package/lib/esm/replicate.js.map +0 -1
  329. package/lib/esm/shared/claude-thinking.js.map +0 -1
  330. package/lib/esm/test-driver/TestErrorCompletionStream.js +0 -16
  331. package/lib/esm/test-driver/TestErrorCompletionStream.js.map +0 -1
  332. package/lib/esm/test-driver/TestValidationErrorCompletionStream.js.map +0 -1
  333. package/lib/esm/test-driver/index.js.map +0 -1
  334. package/lib/esm/test-driver/utils.js.map +0 -1
  335. package/lib/esm/togetherai/index.js +0 -122
  336. package/lib/esm/togetherai/index.js.map +0 -1
  337. package/lib/esm/togetherai/interfaces.js.map +0 -1
  338. package/lib/esm/vertexai/debug.js.map +0 -1
  339. package/lib/esm/vertexai/embeddings/embeddings-image.js +0 -24
  340. package/lib/esm/vertexai/embeddings/embeddings-image.js.map +0 -1
  341. package/lib/esm/vertexai/embeddings/embeddings-text.js +0 -20
  342. package/lib/esm/vertexai/embeddings/embeddings-text.js.map +0 -1
  343. package/lib/esm/vertexai/index.js.map +0 -1
  344. package/lib/esm/vertexai/models/claude.js +0 -906
  345. package/lib/esm/vertexai/models/claude.js.map +0 -1
  346. package/lib/esm/vertexai/models/gemini.js.map +0 -1
  347. package/lib/esm/vertexai/models/imagen.js.map +0 -1
  348. package/lib/esm/vertexai/models/llama.js.map +0 -1
  349. package/lib/esm/vertexai/models.js.map +0 -1
  350. package/lib/esm/watsonx/index.js.map +0 -1
  351. package/lib/esm/xai/index.js.map +0 -1
  352. package/lib/types/adobe/firefly.d.ts.map +0 -1
  353. package/lib/types/azure/azure_foundry.d.ts.map +0 -1
  354. package/lib/types/bedrock/converse.d.ts.map +0 -1
  355. package/lib/types/bedrock/index.d.ts.map +0 -1
  356. package/lib/types/bedrock/nova-image-payload.d.ts.map +0 -1
  357. package/lib/types/bedrock/payloads.d.ts.map +0 -1
  358. package/lib/types/bedrock/s3.d.ts.map +0 -1
  359. package/lib/types/bedrock/twelvelabs.d.ts.map +0 -1
  360. package/lib/types/groq/index.d.ts.map +0 -1
  361. package/lib/types/huggingface_ie.d.ts.map +0 -1
  362. package/lib/types/index.d.ts +0 -15
  363. package/lib/types/index.d.ts.map +0 -1
  364. package/lib/types/mistral/index.d.ts.map +0 -1
  365. package/lib/types/mistral/types.d.ts.map +0 -1
  366. package/lib/types/openai/azure_openai.d.ts.map +0 -1
  367. package/lib/types/openai/index.d.ts.map +0 -1
  368. package/lib/types/openai/openai.d.ts.map +0 -1
  369. package/lib/types/openai/openai_compatible.d.ts.map +0 -1
  370. package/lib/types/openai/openai_format.d.ts.map +0 -1
  371. package/lib/types/replicate.d.ts.map +0 -1
  372. package/lib/types/shared/claude-thinking.d.ts.map +0 -1
  373. package/lib/types/test-driver/TestErrorCompletionStream.d.ts.map +0 -1
  374. package/lib/types/test-driver/TestValidationErrorCompletionStream.d.ts.map +0 -1
  375. package/lib/types/test-driver/index.d.ts.map +0 -1
  376. package/lib/types/test-driver/utils.d.ts.map +0 -1
  377. package/lib/types/togetherai/index.d.ts +0 -23
  378. package/lib/types/togetherai/index.d.ts.map +0 -1
  379. package/lib/types/togetherai/interfaces.d.ts.map +0 -1
  380. package/lib/types/vertexai/debug.d.ts +0 -2
  381. package/lib/types/vertexai/debug.d.ts.map +0 -1
  382. package/lib/types/vertexai/embeddings/embeddings-image.d.ts +0 -11
  383. package/lib/types/vertexai/embeddings/embeddings-image.d.ts.map +0 -1
  384. package/lib/types/vertexai/embeddings/embeddings-text.d.ts +0 -10
  385. package/lib/types/vertexai/embeddings/embeddings-text.d.ts.map +0 -1
  386. package/lib/types/vertexai/index.d.ts.map +0 -1
  387. package/lib/types/vertexai/models/claude.d.ts +0 -119
  388. package/lib/types/vertexai/models/claude.d.ts.map +0 -1
  389. package/lib/types/vertexai/models/gemini.d.ts.map +0 -1
  390. package/lib/types/vertexai/models/imagen.d.ts.map +0 -1
  391. package/lib/types/vertexai/models/llama.d.ts.map +0 -1
  392. package/lib/types/vertexai/models.d.ts +0 -20
  393. package/lib/types/vertexai/models.d.ts.map +0 -1
  394. package/lib/types/watsonx/index.d.ts.map +0 -1
  395. package/lib/types/watsonx/interfaces.d.ts.map +0 -1
  396. package/lib/types/xai/index.d.ts.map +0 -1
  397. package/src/vertexai/embeddings/embeddings-image.ts +0 -52
  398. package/src/vertexai/embeddings/embeddings-text.ts +0 -54
  399. /package/lib/{esm/bedrock → bedrock}/payloads.js +0 -0
  400. /package/lib/{esm/mistral → mistral}/types.js +0 -0
  401. /package/lib/{esm/togetherai → togetherai}/interfaces.js +0 -0
  402. /package/lib/{types/watsonx → watsonx}/interfaces.d.ts +0 -0
  403. /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
  }
@@ -423,8 +501,8 @@ export class GeminiModelDefinition {
423
501
  contents = mergeConsecutiveRole(contents);
424
502
  return { contents, system };
425
503
  }
426
- usageMetadataToTokenUsage(usageMetadata) {
427
- if (!usageMetadata || !usageMetadata.totalTokenCount) {
504
+ usageMetadataToTokenUsage(driver, usageMetadata) {
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
- console.warn("[VertexAI] Gemini token usage mismatch: total does not equal prompt + result", {
442
- total: tokenUsage.total,
443
- prompt: tokenUsage.prompt,
444
- result: tokenUsage.result
445
- });
520
+ // Token-accounting mismatch: warn-level diagnostic (the call still
521
+ // returns the best-effort tokenUsage). Use the driver's structured
522
+ // logger so we don't promote stderr writes to ERROR in serverless
523
+ // log aggregators — see the recoverable-tool-call sites below.
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,49 +547,55 @@ 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
- const token_usage = this.usageMetadataToTokenUsage(response.usageMetadata);
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);
502
584
  // For recoverable tool call issues, log warning but continue processing
503
- // The workflow will handle the invalid tool call gracefully
585
+ // The workflow will handle the invalid tool call gracefully.
586
+ // Route through the driver's structured logger instead of `console.warn`
587
+ // so downstream runtimes (e.g. Cloud Run) don't promote stderr writes
588
+ // to ERROR severity for what is, by definition, a recoverable event.
504
589
  if (isRecoverableToolCall && tool_use && tool_use.length > 0) {
505
- console.warn(`[Gemini] Recoverable tool call issue (${candidate.finishReason}): ` +
506
- `Model tried to call undeclared tool(s): ${tool_use.map(t => t.tool_name).join(', ')}`);
590
+ driver.logger.warn(`[Gemini] Recoverable tool call issue (${candidate.finishReason}): ` +
591
+ `Model tried to call undeclared tool(s): ${tool_use.map((t) => t.tool_name).join(', ')}`);
507
592
  }
508
593
  result = extractCompletionResults(content);
509
594
  conversation = updateConversation(conversation, [content]);
510
595
  }
511
596
  }
512
597
  if (tool_use) {
513
- finish_reason = "tool_use";
598
+ finish_reason = 'tool_use';
514
599
  }
515
600
  // Increment turn counter for deferred stripping
516
601
  conversation = incrementConversationTurn(conversation);
@@ -519,7 +604,7 @@ export class GeminiModelDefinition {
519
604
  const stripOptions = {
520
605
  keepForTurns: options.stripImagesAfterTurns ?? Infinity,
521
606
  currentTurn,
522
- textMaxTokens: options.stripTextMaxTokens
607
+ textMaxTokens: options.stripTextMaxTokens,
523
608
  };
524
609
  let processedConversation = stripBase64ImagesFromConversation(conversation, stripOptions);
525
610
  // Truncate large text content if configured
@@ -532,18 +617,18 @@ export class GeminiModelDefinition {
532
617
  // Preserve system instruction in conversation for multi-turn support
533
618
  const finalConversation = storeSystemInConversation(processedConversation, prompt.system);
534
619
  return {
535
- result: result && result.length > 0 ? result : [{ type: "text", value: '' }],
620
+ result: result && result.length > 0 ? result : [{ type: 'text', value: '' }],
536
621
  token_usage: token_usage,
537
622
  finish_reason: finish_reason,
538
623
  original_response: options.include_original_response ? response : undefined,
539
624
  conversation: finalConversation,
540
- tool_use
625
+ tool_use,
541
626
  };
542
627
  }
543
628
  async requestTextCompletionStream(driver, prompt, options) {
544
- const splits = options.model.split("/");
545
- let region = undefined;
546
- if (splits[0] === "locations" && splits.length >= 2) {
629
+ const splits = options.model.split('/');
630
+ let region;
631
+ if (splits[0] === 'locations' && splits.length >= 2) {
547
632
  region = splits[1];
548
633
  }
549
634
  const modelName = splits[splits.length - 1];
@@ -559,45 +644,51 @@ export class GeminiModelDefinition {
559
644
  // Include conversation history in prompt contents (same as non-streaming)
560
645
  const conversation = updateConversation(options.conversation, prompt.contents);
561
646
  prompt.contents = conversation;
562
- if (options.model.includes("gemini-2.5-flash-image")) {
563
- 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
564
649
  }
565
650
  const model_options = options.model_options;
566
- const client = driver.getGoogleGenAIClient(region, model_options?.flex ?? false);
651
+ const client = driver.getGoogleGenAIClient(region, model_options?.flex ?? false, options.httpTimeout);
567
652
  const payload = getGeminiPayload(options, prompt);
568
653
  const response = await client.models.generateContentStream(payload);
569
654
  const stream = asyncMap(response, async (item) => {
570
- const token_usage = this.usageMetadataToTokenUsage(item.usageMetadata);
655
+ const token_usage = this.usageMetadataToTokenUsage(driver, item.usageMetadata);
571
656
  if (item.candidates && item.candidates.length > 0) {
572
657
  for (const candidate of item.candidates) {
573
658
  let tool_use;
574
659
  let finish_reason;
575
660
  switch (candidate.finishReason) {
576
661
  case FinishReason.MAX_TOKENS:
577
- finish_reason = "length";
662
+ finish_reason = 'length';
578
663
  break;
579
664
  case FinishReason.STOP:
580
- finish_reason = "stop";
665
+ finish_reason = 'stop';
581
666
  break;
582
- default: finish_reason = candidate.finishReason;
667
+ default:
668
+ finish_reason = candidate.finishReason;
583
669
  }
584
670
  // Check for unsupported finish reasons, but allow recoverable tool call issues
585
671
  const isRecoverableToolCall = recoverableToolCallReasons.includes(candidate.finishReason);
586
- if (candidate.finishReason && !supportedFinishReasons.includes(candidate.finishReason) && !isRecoverableToolCall) {
587
- throw new Error(`Unsupported finish reason: ${candidate.finishReason}, `
588
- + `finish message: ${candidate.finishMessage}, `
589
- + `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)}`);
590
678
  }
591
679
  if (candidate.content?.role === 'model') {
592
680
  // Collect all parts in order (text and images)
593
681
  const combinedResults = extractCompletionResults(candidate.content);
594
682
  tool_use = collectToolUseParts(candidate.content);
595
683
  if (tool_use) {
596
- finish_reason = "tool_use";
597
- // Log warning for recoverable tool call issues
684
+ finish_reason = 'tool_use';
685
+ // Log warning for recoverable tool call issues — see the
686
+ // matching site in `requestTextCompletion` above for why
687
+ // we route through the driver's logger instead of
688
+ // `console.warn`.
598
689
  if (isRecoverableToolCall) {
599
- console.warn(`[Gemini] Recoverable tool call issue (${candidate.finishReason}): ` +
600
- `Model tried to call undeclared tool(s): ${tool_use.map(t => t.tool_name).join(', ')}`);
690
+ driver.logger.warn(`[Gemini] Recoverable tool call issue (${candidate.finishReason}): ` +
691
+ `Model tried to call undeclared tool(s): ${tool_use.map((t) => t.tool_name).join(', ')}`);
601
692
  }
602
693
  }
603
694
  return {
@@ -611,8 +702,10 @@ export class GeminiModelDefinition {
611
702
  }
612
703
  //No normal output, returning block reason if it exists.
613
704
  return {
614
- result: item.promptFeedback?.blockReasonMessage ? [{ type: "text", value: item.promptFeedback.blockReasonMessage }] : [],
615
- finish_reason: item.promptFeedback?.blockReason ?? "",
705
+ result: item.promptFeedback?.blockReasonMessage
706
+ ? [{ type: 'text', value: item.promptFeedback.blockReasonMessage }]
707
+ : [],
708
+ finish_reason: item.promptFeedback?.blockReason ?? '',
616
709
  token_usage: token_usage,
617
710
  };
618
711
  });
@@ -649,7 +742,7 @@ export class GeminiModelDefinition {
649
742
  const apiError = error;
650
743
  const httpStatusCode = apiError.status;
651
744
  // Extract error message
652
- const message = apiError.message || String(error);
745
+ const message = apiError.message;
653
746
  // Build user-facing message with status code
654
747
  let userMessage = message;
655
748
  // Include status code in message (for end-user visibility)
@@ -657,7 +750,7 @@ export class GeminiModelDefinition {
657
750
  userMessage = `[${httpStatusCode}] ${userMessage}`;
658
751
  }
659
752
  // Determine retryability based on Google error codes
660
- const retryable = this.isGeminiErrorRetryable(httpStatusCode);
753
+ const retryable = this.isGeminiErrorRetryable(httpStatusCode, message);
661
754
  // Extract error name/type from message if present
662
755
  const errorName = this.extractErrorName(message);
663
756
  return new LlumiverseError(`[${context.provider}] ${userMessage}`, retryable, context, error, httpStatusCode, errorName);
@@ -670,13 +763,15 @@ export class GeminiModelDefinition {
670
763
  typeof error === 'object' &&
671
764
  'status' in error &&
672
765
  typeof error.status === 'number' &&
673
- 'message' in error);
766
+ 'message' in error &&
767
+ typeof error.message === 'string');
674
768
  }
675
769
  /**
676
770
  * Determine if a Google API error is retryable based on HTTP status code.
677
771
  *
678
772
  * Retryable errors (per Google AIP-194):
679
773
  * - 408 (REQUEST_TIMEOUT): Request timeout
774
+ * - 499 (CANCELLED / Client Closed Request): Transport cancellation
680
775
  * - 429 (RESOURCE_EXHAUSTED): Rate limit exceeded, quota exhausted
681
776
  * - 500 (INTERNAL): Internal server error
682
777
  * - 502 (BAD_GATEWAY): Bad gateway
@@ -691,15 +786,26 @@ export class GeminiModelDefinition {
691
786
  * - 409 (CONFLICT): Resource conflict
692
787
  * - Other 4xx client errors
693
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
+ *
694
795
  * @param httpStatusCode - The HTTP status code from the API error
796
+ * @param message - The error message (used to detect transient 400 sub-cases)
695
797
  * @returns True if retryable, false if not retryable, undefined if unknown
696
798
  */
697
- isGeminiErrorRetryable(httpStatusCode) {
799
+ isGeminiErrorRetryable(httpStatusCode, message) {
800
+ if (message && this.isNonRetryableAuthError(message))
801
+ return false;
698
802
  // Retryable status codes
699
803
  if (httpStatusCode === 408)
700
804
  return true; // Request timeout
701
805
  if (httpStatusCode === 429)
702
806
  return true; // Rate limit/quota
807
+ if (httpStatusCode === 499)
808
+ return true; // Client closed / operation cancelled
703
809
  if (httpStatusCode === 502)
704
810
  return true; // Bad gateway
705
811
  if (httpStatusCode === 503)
@@ -708,12 +814,32 @@ export class GeminiModelDefinition {
708
814
  return true; // Gateway timeout
709
815
  if (httpStatusCode >= 500 && httpStatusCode < 600)
710
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
+ }
711
833
  // Non-retryable 4xx client errors
712
834
  if (httpStatusCode >= 400 && httpStatusCode < 500)
713
835
  return false;
714
836
  // Unknown status codes - let consumer decide retry strategy
715
837
  return undefined;
716
838
  }
839
+ isNonRetryableAuthError(message) {
840
+ const lowerMessage = message.toLowerCase();
841
+ return lowerMessage.includes('invalid_grant') || lowerMessage.includes("credential's issuer");
842
+ }
717
843
  /**
718
844
  * Extract error type name from error message.
719
845
  * Google errors often include the error type in the message.
@@ -722,6 +848,7 @@ export class GeminiModelDefinition {
722
848
  extractErrorName(message) {
723
849
  // Common Google error patterns
724
850
  const patterns = [
851
+ /^Error code ([a-zA-Z0-9_-]+):/, // "Error code invalid_grant: message"
725
852
  /^([A-Z_]+):/, // "ERROR_NAME: message"
726
853
  /\[([A-Z_]+)\]/, // "[ERROR_NAME] message"
727
854
  /^(\w+Error):/, // "ErrorTypeError: message"
@@ -741,22 +868,23 @@ export class GeminiModelDefinition {
741
868
  * tools/toolConfig to be defined in the API request.
742
869
  */
743
870
  export function convertGeminiFunctionPartsToText(contents) {
744
- return contents.map(content => {
871
+ return contents.map((content) => {
745
872
  if (!content.parts)
746
873
  return content;
747
- const hasFunctionParts = content.parts.some(p => p.functionCall || p.functionResponse);
874
+ const hasFunctionParts = content.parts.some((p) => p.functionCall || p.functionResponse);
748
875
  if (!hasFunctionParts)
749
876
  return content;
750
- const newParts = content.parts.map(part => {
877
+ const newParts = content.parts.map((part) => {
751
878
  if (part.functionCall) {
752
879
  const argsStr = part.functionCall.args ? JSON.stringify(part.functionCall.args) : '';
753
- const truncated = argsStr.length > 500 ? argsStr.substring(0, 500) + '...' : argsStr;
880
+ const truncated = argsStr.length > 500 ? `${argsStr.substring(0, 500)}...` : argsStr;
754
881
  return { text: `[Tool call: ${part.functionCall.name}(${truncated})]` };
755
882
  }
756
883
  if (part.functionResponse) {
757
884
  const respStr = part.functionResponse.response
758
- ? JSON.stringify(part.functionResponse.response) : 'No response';
759
- 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;
760
888
  return { text: `[Tool result for ${part.functionResponse.name}: ${truncated}]` };
761
889
  }
762
890
  return part;
@@ -837,11 +965,11 @@ function storeSystemInConversation(conversation, system) {
837
965
  */
838
966
  function formatFunctionResponse(response) {
839
967
  response = response.trim();
840
- if (response.startsWith("{") && response.endsWith("}")) {
968
+ if (response.startsWith('{') && response.endsWith('}')) {
841
969
  try {
842
970
  return JSON.parse(response);
843
971
  }
844
- catch (e) {
972
+ catch {
845
973
  return { output: response };
846
974
  }
847
975
  }