@llumiverse/drivers 0.22.0 → 0.23.0-dev-20251118

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 (295) hide show
  1. package/README.md +1 -1
  2. package/lib/cjs/adobe/firefly.js +8 -7
  3. package/lib/cjs/adobe/firefly.js.map +1 -1
  4. package/lib/cjs/azure/azure_foundry.js +12 -12
  5. package/lib/cjs/azure/azure_foundry.js.map +1 -1
  6. package/lib/cjs/bedrock/index.js +172 -22
  7. package/lib/cjs/bedrock/index.js.map +1 -1
  8. package/lib/cjs/bedrock/twelvelabs.js +87 -0
  9. package/lib/cjs/bedrock/twelvelabs.js.map +1 -0
  10. package/lib/cjs/groq/index.js +91 -16
  11. package/lib/cjs/groq/index.js.map +1 -1
  12. package/lib/cjs/huggingface_ie.js +7 -6
  13. package/lib/cjs/huggingface_ie.js.map +1 -1
  14. package/lib/cjs/index.js +2 -2
  15. package/lib/cjs/index.js.map +1 -1
  16. package/lib/cjs/mistral/index.js +5 -4
  17. package/lib/cjs/mistral/index.js.map +1 -1
  18. package/lib/cjs/openai/azure_openai.js +1 -1
  19. package/lib/cjs/openai/azure_openai.js.map +1 -1
  20. package/lib/cjs/openai/index.js +16 -12
  21. package/lib/cjs/openai/index.js.map +1 -1
  22. package/lib/cjs/replicate.js +6 -6
  23. package/lib/cjs/replicate.js.map +1 -1
  24. package/lib/cjs/test/utils.js +1 -1
  25. package/lib/cjs/test/utils.js.map +1 -1
  26. package/lib/cjs/test-driver/TestErrorCompletionStream.js +20 -0
  27. package/lib/cjs/test-driver/TestErrorCompletionStream.js.map +1 -0
  28. package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js +24 -0
  29. package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js.map +1 -0
  30. package/lib/cjs/test-driver/index.js +109 -0
  31. package/lib/cjs/test-driver/index.js.map +1 -0
  32. package/lib/cjs/test-driver/utils.js +30 -0
  33. package/lib/cjs/test-driver/utils.js.map +1 -0
  34. package/lib/cjs/togetherai/index.js +4 -4
  35. package/lib/cjs/togetherai/index.js.map +1 -1
  36. package/lib/cjs/vertexai/embeddings/embeddings-text.js +1 -1
  37. package/lib/cjs/vertexai/embeddings/embeddings-text.js.map +1 -1
  38. package/lib/cjs/vertexai/index.js +136 -31
  39. package/lib/cjs/vertexai/index.js.map +1 -1
  40. package/lib/cjs/vertexai/models/claude.js +38 -16
  41. package/lib/cjs/vertexai/models/claude.js.map +1 -1
  42. package/lib/cjs/vertexai/models/gemini.js +131 -41
  43. package/lib/cjs/vertexai/models/gemini.js.map +1 -1
  44. package/lib/cjs/vertexai/models/imagen.js +12 -23
  45. package/lib/cjs/vertexai/models/imagen.js.map +1 -1
  46. package/lib/cjs/vertexai/models/llama.js +4 -3
  47. package/lib/cjs/vertexai/models/llama.js.map +1 -1
  48. package/lib/cjs/vertexai/models.js +13 -2
  49. package/lib/cjs/vertexai/models.js.map +1 -1
  50. package/lib/cjs/watsonx/index.js +5 -5
  51. package/lib/cjs/watsonx/index.js.map +1 -1
  52. package/lib/cjs/xai/index.js +1 -1
  53. package/lib/cjs/xai/index.js.map +1 -1
  54. package/lib/esm/adobe/firefly.js +8 -7
  55. package/lib/esm/adobe/firefly.js.map +1 -1
  56. package/lib/esm/azure/azure_foundry.js +12 -12
  57. package/lib/esm/azure/azure_foundry.js.map +1 -1
  58. package/lib/esm/bedrock/index.js +172 -22
  59. package/lib/esm/bedrock/index.js.map +1 -1
  60. package/lib/esm/bedrock/twelvelabs.js +84 -0
  61. package/lib/esm/bedrock/twelvelabs.js.map +1 -0
  62. package/lib/esm/groq/index.js +91 -16
  63. package/lib/esm/groq/index.js.map +1 -1
  64. package/lib/esm/huggingface_ie.js +8 -7
  65. package/lib/esm/huggingface_ie.js.map +1 -1
  66. package/lib/esm/index.js +2 -2
  67. package/lib/esm/index.js.map +1 -1
  68. package/lib/esm/mistral/index.js +5 -4
  69. package/lib/esm/mistral/index.js.map +1 -1
  70. package/lib/esm/openai/azure_openai.js +1 -1
  71. package/lib/esm/openai/azure_openai.js.map +1 -1
  72. package/lib/esm/openai/index.js +16 -12
  73. package/lib/esm/openai/index.js.map +1 -1
  74. package/lib/esm/replicate.js +6 -6
  75. package/lib/esm/replicate.js.map +1 -1
  76. package/lib/esm/src/adobe/firefly.js +116 -0
  77. package/lib/esm/src/adobe/firefly.js.map +1 -0
  78. package/lib/esm/src/azure/azure_foundry.js +382 -0
  79. package/lib/esm/src/azure/azure_foundry.js.map +1 -0
  80. package/lib/esm/src/bedrock/converse.js +278 -0
  81. package/lib/esm/src/bedrock/converse.js.map +1 -0
  82. package/lib/esm/src/bedrock/index.js +962 -0
  83. package/lib/esm/src/bedrock/index.js.map +1 -0
  84. package/lib/esm/src/bedrock/nova-image-payload.js +203 -0
  85. package/lib/esm/src/bedrock/nova-image-payload.js.map +1 -0
  86. package/lib/esm/src/bedrock/payloads.js +2 -0
  87. package/lib/esm/src/bedrock/payloads.js.map +1 -0
  88. package/lib/esm/src/bedrock/s3.js +99 -0
  89. package/lib/esm/src/bedrock/s3.js.map +1 -0
  90. package/lib/esm/src/bedrock/twelvelabs.js +84 -0
  91. package/lib/esm/src/bedrock/twelvelabs.js.map +1 -0
  92. package/lib/esm/src/groq/index.js +286 -0
  93. package/lib/esm/src/groq/index.js.map +1 -0
  94. package/lib/esm/src/huggingface_ie.js +197 -0
  95. package/lib/esm/src/huggingface_ie.js.map +1 -0
  96. package/lib/esm/src/index.js +14 -0
  97. package/lib/esm/src/index.js.map +1 -0
  98. package/lib/esm/src/mistral/index.js +169 -0
  99. package/lib/esm/src/mistral/index.js.map +1 -0
  100. package/lib/esm/src/mistral/types.js +80 -0
  101. package/lib/esm/src/mistral/types.js.map +1 -0
  102. package/lib/esm/src/openai/azure_openai.js +68 -0
  103. package/lib/esm/src/openai/azure_openai.js.map +1 -0
  104. package/lib/esm/src/openai/index.js +464 -0
  105. package/lib/esm/src/openai/index.js.map +1 -0
  106. package/lib/esm/src/openai/openai.js +14 -0
  107. package/lib/esm/src/openai/openai.js.map +1 -0
  108. package/lib/esm/src/openai/openai_format.js +134 -0
  109. package/lib/esm/src/openai/openai_format.js.map +1 -0
  110. package/lib/esm/src/replicate.js +268 -0
  111. package/lib/esm/src/replicate.js.map +1 -0
  112. package/lib/esm/src/test/TestErrorCompletionStream.js +16 -0
  113. package/lib/esm/src/test/TestErrorCompletionStream.js.map +1 -0
  114. package/lib/esm/src/test/TestValidationErrorCompletionStream.js +20 -0
  115. package/lib/esm/src/test/TestValidationErrorCompletionStream.js.map +1 -0
  116. package/lib/esm/src/test/index.js +91 -0
  117. package/lib/esm/src/test/index.js.map +1 -0
  118. package/lib/esm/src/test/utils.js +25 -0
  119. package/lib/esm/src/test/utils.js.map +1 -0
  120. package/lib/esm/src/test-driver/TestErrorCompletionStream.js +16 -0
  121. package/lib/esm/src/test-driver/TestErrorCompletionStream.js.map +1 -0
  122. package/lib/esm/src/test-driver/TestValidationErrorCompletionStream.js +20 -0
  123. package/lib/esm/src/test-driver/TestValidationErrorCompletionStream.js.map +1 -0
  124. package/lib/esm/src/test-driver/index.js +91 -0
  125. package/lib/esm/src/test-driver/index.js.map +1 -0
  126. package/lib/esm/src/test-driver/utils.js +25 -0
  127. package/lib/esm/src/test-driver/utils.js.map +1 -0
  128. package/lib/esm/src/togetherai/index.js +122 -0
  129. package/lib/esm/src/togetherai/index.js.map +1 -0
  130. package/lib/esm/src/togetherai/interfaces.js +2 -0
  131. package/lib/esm/src/togetherai/interfaces.js.map +1 -0
  132. package/lib/esm/src/vertexai/debug.js +6 -0
  133. package/lib/esm/src/vertexai/debug.js.map +1 -0
  134. package/lib/esm/src/vertexai/embeddings/embeddings-image.js +24 -0
  135. package/lib/esm/src/vertexai/embeddings/embeddings-image.js.map +1 -0
  136. package/lib/esm/src/vertexai/embeddings/embeddings-text.js +20 -0
  137. package/lib/esm/src/vertexai/embeddings/embeddings-text.js.map +1 -0
  138. package/lib/esm/src/vertexai/index.js +383 -0
  139. package/lib/esm/src/vertexai/index.js.map +1 -0
  140. package/lib/esm/src/vertexai/models/claude.js +394 -0
  141. package/lib/esm/src/vertexai/models/claude.js.map +1 -0
  142. package/lib/esm/src/vertexai/models/gemini.js +817 -0
  143. package/lib/esm/src/vertexai/models/gemini.js.map +1 -0
  144. package/lib/esm/src/vertexai/models/imagen.js +302 -0
  145. package/lib/esm/src/vertexai/models/imagen.js.map +1 -0
  146. package/lib/esm/src/vertexai/models/llama.js +179 -0
  147. package/lib/esm/src/vertexai/models/llama.js.map +1 -0
  148. package/lib/esm/src/vertexai/models.js +32 -0
  149. package/lib/esm/src/vertexai/models.js.map +1 -0
  150. package/lib/esm/src/watsonx/index.js +157 -0
  151. package/lib/esm/src/watsonx/index.js.map +1 -0
  152. package/lib/esm/src/watsonx/interfaces.js +2 -0
  153. package/lib/esm/src/watsonx/interfaces.js.map +1 -0
  154. package/lib/esm/src/xai/index.js +64 -0
  155. package/lib/esm/src/xai/index.js.map +1 -0
  156. package/lib/esm/test/utils.js +1 -1
  157. package/lib/esm/test/utils.js.map +1 -1
  158. package/lib/esm/test-driver/TestErrorCompletionStream.js +16 -0
  159. package/lib/esm/test-driver/TestErrorCompletionStream.js.map +1 -0
  160. package/lib/esm/test-driver/TestValidationErrorCompletionStream.js +20 -0
  161. package/lib/esm/test-driver/TestValidationErrorCompletionStream.js.map +1 -0
  162. package/lib/esm/test-driver/index.js +91 -0
  163. package/lib/esm/test-driver/index.js.map +1 -0
  164. package/lib/esm/test-driver/utils.js +25 -0
  165. package/lib/esm/test-driver/utils.js.map +1 -0
  166. package/lib/esm/togetherai/index.js +4 -4
  167. package/lib/esm/togetherai/index.js.map +1 -1
  168. package/lib/esm/tsconfig.tsbuildinfo +1 -0
  169. package/lib/esm/vertexai/embeddings/embeddings-text.js +1 -1
  170. package/lib/esm/vertexai/embeddings/embeddings-text.js.map +1 -1
  171. package/lib/esm/vertexai/index.js +136 -31
  172. package/lib/esm/vertexai/index.js.map +1 -1
  173. package/lib/esm/vertexai/models/claude.js +37 -15
  174. package/lib/esm/vertexai/models/claude.js.map +1 -1
  175. package/lib/esm/vertexai/models/gemini.js +133 -43
  176. package/lib/esm/vertexai/models/gemini.js.map +1 -1
  177. package/lib/esm/vertexai/models/imagen.js +9 -17
  178. package/lib/esm/vertexai/models/imagen.js.map +1 -1
  179. package/lib/esm/vertexai/models/llama.js +4 -3
  180. package/lib/esm/vertexai/models/llama.js.map +1 -1
  181. package/lib/esm/vertexai/models.js +13 -2
  182. package/lib/esm/vertexai/models.js.map +1 -1
  183. package/lib/esm/watsonx/index.js +5 -5
  184. package/lib/esm/watsonx/index.js.map +1 -1
  185. package/lib/esm/xai/index.js +1 -1
  186. package/lib/esm/xai/index.js.map +1 -1
  187. package/lib/types/adobe/firefly.d.ts +3 -3
  188. package/lib/types/adobe/firefly.d.ts.map +1 -1
  189. package/lib/types/azure/azure_foundry.d.ts +2 -2
  190. package/lib/types/azure/azure_foundry.d.ts.map +1 -1
  191. package/lib/types/bedrock/index.d.ts +9 -5
  192. package/lib/types/bedrock/index.d.ts.map +1 -1
  193. package/lib/types/bedrock/twelvelabs.d.ts +50 -0
  194. package/lib/types/bedrock/twelvelabs.d.ts.map +1 -0
  195. package/lib/types/groq/index.d.ts +3 -0
  196. package/lib/types/groq/index.d.ts.map +1 -1
  197. package/lib/types/huggingface_ie.d.ts +8 -5
  198. package/lib/types/huggingface_ie.d.ts.map +1 -1
  199. package/lib/types/index.d.ts +2 -2
  200. package/lib/types/index.d.ts.map +1 -1
  201. package/lib/types/mistral/index.d.ts +2 -2
  202. package/lib/types/mistral/index.d.ts.map +1 -1
  203. package/lib/types/openai/index.d.ts +2 -2
  204. package/lib/types/openai/index.d.ts.map +1 -1
  205. package/lib/types/replicate.d.ts +6 -3
  206. package/lib/types/replicate.d.ts.map +1 -1
  207. package/lib/types/src/adobe/firefly.d.ts +29 -0
  208. package/lib/types/src/azure/azure_foundry.d.ts +49 -0
  209. package/lib/types/src/bedrock/converse.d.ts +8 -0
  210. package/lib/types/src/bedrock/index.d.ts +61 -0
  211. package/lib/types/src/bedrock/nova-image-payload.d.ts +73 -0
  212. package/lib/types/src/bedrock/payloads.d.ts +11 -0
  213. package/lib/types/src/bedrock/s3.d.ts +22 -0
  214. package/lib/types/src/bedrock/twelvelabs.d.ts +49 -0
  215. package/lib/types/src/groq/index.d.ts +26 -0
  216. package/lib/types/src/huggingface_ie.d.ts +34 -0
  217. package/lib/types/src/index.d.ts +13 -0
  218. package/lib/types/src/mistral/index.d.ts +24 -0
  219. package/lib/types/src/mistral/types.d.ts +131 -0
  220. package/lib/types/src/openai/azure_openai.d.ts +24 -0
  221. package/lib/types/src/openai/index.d.ts +24 -0
  222. package/lib/types/src/openai/openai.d.ts +14 -0
  223. package/lib/types/src/openai/openai_format.d.ts +18 -0
  224. package/lib/types/src/replicate.d.ts +47 -0
  225. package/lib/types/src/test/TestErrorCompletionStream.d.ts +8 -0
  226. package/lib/types/src/test/TestValidationErrorCompletionStream.d.ts +8 -0
  227. package/lib/types/src/test/index.d.ts +23 -0
  228. package/lib/types/src/test/utils.d.ts +4 -0
  229. package/lib/types/src/test-driver/TestErrorCompletionStream.d.ts +8 -0
  230. package/lib/types/src/test-driver/TestValidationErrorCompletionStream.d.ts +8 -0
  231. package/lib/types/src/test-driver/index.d.ts +23 -0
  232. package/lib/types/src/test-driver/utils.d.ts +4 -0
  233. package/lib/types/src/togetherai/index.d.ts +22 -0
  234. package/lib/types/src/togetherai/interfaces.d.ts +95 -0
  235. package/lib/types/src/vertexai/debug.d.ts +1 -0
  236. package/lib/types/src/vertexai/embeddings/embeddings-image.d.ts +10 -0
  237. package/lib/types/src/vertexai/embeddings/embeddings-text.d.ts +9 -0
  238. package/lib/types/src/vertexai/index.d.ts +52 -0
  239. package/lib/types/src/vertexai/models/claude.d.ts +19 -0
  240. package/lib/types/src/vertexai/models/gemini.d.ts +17 -0
  241. package/lib/types/src/vertexai/models/imagen.d.ts +74 -0
  242. package/lib/types/src/vertexai/models/llama.d.ts +19 -0
  243. package/lib/types/src/vertexai/models.d.ts +14 -0
  244. package/lib/types/src/watsonx/index.d.ts +26 -0
  245. package/lib/types/src/watsonx/interfaces.d.ts +64 -0
  246. package/lib/types/src/xai/index.d.ts +18 -0
  247. package/lib/types/test-driver/TestErrorCompletionStream.d.ts +9 -0
  248. package/lib/types/test-driver/TestErrorCompletionStream.d.ts.map +1 -0
  249. package/lib/types/test-driver/TestValidationErrorCompletionStream.d.ts +9 -0
  250. package/lib/types/test-driver/TestValidationErrorCompletionStream.d.ts.map +1 -0
  251. package/lib/types/test-driver/index.d.ts +24 -0
  252. package/lib/types/test-driver/index.d.ts.map +1 -0
  253. package/lib/types/test-driver/utils.d.ts +5 -0
  254. package/lib/types/test-driver/utils.d.ts.map +1 -0
  255. package/lib/types/togetherai/index.d.ts +3 -3
  256. package/lib/types/togetherai/index.d.ts.map +1 -1
  257. package/lib/types/vertexai/index.d.ts +17 -14
  258. package/lib/types/vertexai/index.d.ts.map +1 -1
  259. package/lib/types/vertexai/models/claude.d.ts +2 -0
  260. package/lib/types/vertexai/models/claude.d.ts.map +1 -1
  261. package/lib/types/vertexai/models/gemini.d.ts.map +1 -1
  262. package/lib/types/vertexai/models/imagen.d.ts +2 -2
  263. package/lib/types/vertexai/models/imagen.d.ts.map +1 -1
  264. package/lib/types/vertexai/models/llama.d.ts +2 -2
  265. package/lib/types/vertexai/models/llama.d.ts.map +1 -1
  266. package/lib/types/vertexai/models.d.ts +2 -2
  267. package/lib/types/vertexai/models.d.ts.map +1 -1
  268. package/lib/types/watsonx/index.d.ts +3 -3
  269. package/lib/types/watsonx/index.d.ts.map +1 -1
  270. package/package.json +90 -85
  271. package/src/adobe/firefly.ts +14 -22
  272. package/src/azure/azure_foundry.ts +16 -16
  273. package/src/bedrock/index.ts +207 -28
  274. package/src/bedrock/twelvelabs.ts +150 -0
  275. package/src/groq/index.ts +134 -37
  276. package/src/huggingface_ie.ts +13 -14
  277. package/src/index.ts +2 -2
  278. package/src/mistral/index.ts +8 -7
  279. package/src/openai/azure_openai.ts +5 -5
  280. package/src/openai/index.ts +19 -13
  281. package/src/replicate.ts +14 -14
  282. package/src/{test → test-driver}/utils.ts +1 -1
  283. package/src/togetherai/index.ts +7 -7
  284. package/src/vertexai/embeddings/embeddings-text.ts +2 -2
  285. package/src/vertexai/index.ts +156 -40
  286. package/src/vertexai/models/claude.ts +45 -19
  287. package/src/vertexai/models/gemini.ts +161 -60
  288. package/src/vertexai/models/imagen.ts +15 -26
  289. package/src/vertexai/models/llama.ts +6 -5
  290. package/src/vertexai/models.ts +18 -6
  291. package/src/watsonx/index.ts +8 -8
  292. package/src/xai/index.ts +11 -12
  293. /package/src/{test → test-driver}/TestErrorCompletionStream.ts +0 -0
  294. /package/src/{test → test-driver}/TestValidationErrorCompletionStream.ts +0 -0
  295. /package/src/{test → test-driver}/index.ts +0 -0
@@ -9,6 +9,17 @@ import { ModelDefinition } from "../models.js";
9
9
  import { MessageCreateParamsBase, MessageCreateParamsNonStreaming, RawMessageStreamEvent } from "@anthropic-ai/sdk/resources/messages.js";
10
10
  import { MessageStreamParams } from "@anthropic-ai/sdk/resources/index.mjs";
11
11
 
12
+ export const ANTHROPIC_REGIONS: Record<string, string> = {
13
+ us: "us-east5",
14
+ europe: "europe-west1",
15
+ global: "global",
16
+ }
17
+
18
+ export const NON_GLOBAL_ANTHROPIC_MODELS = [
19
+ "claude-3-5",
20
+ "claude-3",
21
+ ];
22
+
12
23
  interface ClaudePrompt {
13
24
  messages: MessageParam[];
14
25
  system?: TextBlockParam[];
@@ -87,7 +98,7 @@ async function collectFileBlocks(segment: PromptSegment, restrictedTypes: true):
87
98
  async function collectFileBlocks(segment: PromptSegment, restrictedTypes?: false): Promise<ContentBlockParam[]>;
88
99
  async function collectFileBlocks(segment: PromptSegment, restrictedTypes: boolean = false): Promise<ContentBlockParam[]> {
89
100
  const contentBlocks: ContentBlockParam[] = [];
90
-
101
+
91
102
  for (const file of segment.files || []) {
92
103
  if (file.mime_type?.startsWith("image/")) {
93
104
  const allowedTypes = ["image/png", "image/jpeg", "image/gif", "image/webp"];
@@ -128,7 +139,7 @@ async function collectFileBlocks(segment: PromptSegment, restrictedTypes: boolea
128
139
  }
129
140
  }
130
141
  }
131
-
142
+
132
143
  return contentBlocks;
133
144
  }
134
145
 
@@ -191,7 +202,7 @@ export class ClaudeModelDefinition implements ModelDefinition<ClaudePrompt> {
191
202
  text: segment.content
192
203
  } satisfies TextBlockParam);
193
204
  }
194
-
205
+
195
206
  // Collect file blocks with type safety
196
207
  const fileBlocks = await collectFileBlocks(segment, true);
197
208
  contentBlocks.push(...fileBlocks);
@@ -208,7 +219,7 @@ export class ClaudeModelDefinition implements ModelDefinition<ClaudePrompt> {
208
219
  } else {
209
220
  // Build content blocks for regular messages (all types allowed)
210
221
  const contentBlocks: ContentBlockParam[] = [];
211
-
222
+
212
223
  if (segment.content) {
213
224
  contentBlocks.push({
214
225
  type: 'text',
@@ -250,11 +261,19 @@ export class ClaudeModelDefinition implements ModelDefinition<ClaudePrompt> {
250
261
  }
251
262
 
252
263
  async requestTextCompletion(driver: VertexAIDriver, prompt: ClaudePrompt, options: ExecutionOptions): Promise<Completion> {
253
- const client = driver.getAnthropicClient();
264
+ const splits = options.model.split("/");
265
+ let region: string | undefined = undefined;
266
+ if (splits[0] === "locations" && splits.length >= 2) {
267
+ region = splits[1];
268
+ }
269
+ const modelName = splits[splits.length - 1];
270
+ options = { ...options, model: modelName };
271
+
272
+ const client = await driver.getAnthropicClient(region);
254
273
  options.model_options = options.model_options as VertexAIClaudeOptions;
255
274
 
256
275
  if (options.model_options?._option_id !== "vertexai-claude") {
257
- driver.logger.warn("Invalid model options", { options: options.model_options });
276
+ driver.logger.warn({ options: options.model_options }, "Invalid model options");
258
277
  }
259
278
 
260
279
  let conversation = updateConversation(options.conversation as ClaudePrompt, prompt);
@@ -273,7 +292,7 @@ export class ClaudeModelDefinition implements ModelDefinition<ClaudePrompt> {
273
292
  conversation = updateConversation(conversation, createPromptFromResponse(result));
274
293
 
275
294
  return {
276
- result: text ?? '',
295
+ result: text ? [{ type: "text", value: text }] : [{ type: "text", value: '' }],
277
296
  tool_use,
278
297
  token_usage: {
279
298
  prompt: result.usage.input_tokens,
@@ -287,11 +306,19 @@ export class ClaudeModelDefinition implements ModelDefinition<ClaudePrompt> {
287
306
  }
288
307
 
289
308
  async requestTextCompletionStream(driver: VertexAIDriver, prompt: ClaudePrompt, options: ExecutionOptions): Promise<AsyncIterable<CompletionChunkObject>> {
290
- const client = driver.getAnthropicClient();
309
+ const splits = options.model.split("/");
310
+ let region: string | undefined = undefined;
311
+ if (splits[0] === "locations" && splits.length >= 2) {
312
+ region = splits[1];
313
+ }
314
+ const modelName = splits[splits.length - 1];
315
+ options = { ...options, model: modelName };
316
+
317
+ const client = await driver.getAnthropicClient(region);
291
318
  const model_options = options.model_options as VertexAIClaudeOptions | undefined;
292
319
 
293
320
  if (model_options?._option_id !== "vertexai-claude") {
294
- driver.logger.warn("Invalid model options", { options: options.model_options });
321
+ driver.logger.warn({ options: options.model_options }, "Invalid model options");
295
322
  }
296
323
 
297
324
  const { payload, requestOptions } = getClaudePayload(options, prompt);
@@ -303,7 +330,7 @@ export class ClaudeModelDefinition implements ModelDefinition<ClaudePrompt> {
303
330
  switch (streamEvent.type) {
304
331
  case "message_start":
305
332
  return {
306
- result: '',
333
+ result: [{ type: "text", value: '' }],
307
334
  token_usage: {
308
335
  prompt: streamEvent.message.usage.input_tokens,
309
336
  result: streamEvent.message.usage.output_tokens
@@ -311,7 +338,7 @@ export class ClaudeModelDefinition implements ModelDefinition<ClaudePrompt> {
311
338
  } satisfies CompletionChunkObject;
312
339
  case "message_delta":
313
340
  return {
314
- result: '',
341
+ result: [{ type: "text", value: '' }],
315
342
  token_usage: {
316
343
  result: streamEvent.usage.output_tokens
317
344
  },
@@ -321,7 +348,7 @@ export class ClaudeModelDefinition implements ModelDefinition<ClaudePrompt> {
321
348
  // Handle redacted thinking blocks
322
349
  if (streamEvent.content_block.type === "redacted_thinking" && model_options?.include_thoughts) {
323
350
  return {
324
- result: `[Redacted thinking: ${streamEvent.content_block.data}]`
351
+ result: [{ type: "text", value: `[Redacted thinking: ${streamEvent.content_block.data}]` }]
325
352
  } satisfies CompletionChunkObject;
326
353
  }
327
354
  break;
@@ -330,12 +357,12 @@ export class ClaudeModelDefinition implements ModelDefinition<ClaudePrompt> {
330
357
  switch (streamEvent.delta.type) {
331
358
  case "text_delta":
332
359
  return {
333
- result: streamEvent.delta.text ?? ''
360
+ result: streamEvent.delta.text ? [{ type: "text", value: streamEvent.delta.text }] : []
334
361
  } satisfies CompletionChunkObject;
335
362
  case "thinking_delta":
336
363
  if (model_options?.include_thoughts) {
337
364
  return {
338
- result: streamEvent.delta.thinking ?? '',
365
+ result: streamEvent.delta.thinking ? [{ type: "text", value: streamEvent.delta.thinking }] : [],
339
366
  } satisfies CompletionChunkObject;
340
367
  }
341
368
  break;
@@ -343,7 +370,7 @@ export class ClaudeModelDefinition implements ModelDefinition<ClaudePrompt> {
343
370
  // Signature deltas, signify the end of the thoughts.
344
371
  if (model_options?.include_thoughts) {
345
372
  return {
346
- result: '\n\n', // Double newline for more spacing
373
+ result: [{ type: "text", value: '\n\n' }], // Double newline for more spacing
347
374
  } satisfies CompletionChunkObject;
348
375
  }
349
376
  break;
@@ -353,7 +380,7 @@ export class ClaudeModelDefinition implements ModelDefinition<ClaudePrompt> {
353
380
  // Handle the end of content blocks, for redacted thinking blocks
354
381
  if (model_options?.include_thoughts) {
355
382
  return {
356
- result: '\n\n' // Add double newline for spacing
383
+ result: [{ type: "text", value: '\n\n' }] // Add double newline for spacing
357
384
  } satisfies CompletionChunkObject;
358
385
  }
359
386
  break;
@@ -361,7 +388,7 @@ export class ClaudeModelDefinition implements ModelDefinition<ClaudePrompt> {
361
388
 
362
389
  // Default case for all other event types
363
390
  return {
364
- result: ''
391
+ result: []
365
392
  } satisfies CompletionChunkObject;
366
393
  });
367
394
 
@@ -399,8 +426,7 @@ interface RequestOptions {
399
426
  }
400
427
 
401
428
  function getClaudePayload(options: ExecutionOptions, prompt: ClaudePrompt): { payload: MessageCreateParamsBase, requestOptions: RequestOptions | undefined } {
402
- const splits = options.model.split("/");
403
- const modelName = splits[splits.length - 1];
429
+ const modelName = options.model; // Model name is already extracted in the calling methods
404
430
  const model_options = options.model_options as VertexAIClaudeOptions;
405
431
 
406
432
  // Add beta header for Claude 3.7 models to enable 128k output tokens
@@ -1,12 +1,13 @@
1
1
  import {
2
- Content, FinishReason, FunctionCallingConfigMode, FunctionDeclaration, GenerateContentParameters,
2
+ Content, FinishReason, FunctionCallingConfigMode, FunctionDeclaration, GenerateContentConfig, GenerateContentParameters,
3
3
  GenerateContentResponseUsageMetadata,
4
- HarmBlockThreshold, HarmCategory, Part, SafetySetting, Schema, Tool, Type
4
+ HarmBlockThreshold, HarmCategory, Modality, Part, SafetySetting, Schema, Tool, Type
5
5
  } from "@google/genai";
6
6
  import {
7
- AIModel, Completion, CompletionChunkObject, ExecutionOptions,
8
- ExecutionTokenUsage, JSONObject, JSONSchema, ModelType, PromptOptions, PromptRole,
9
- PromptSegment, readStreamAsBase64, ToolDefinition, ToolUse
7
+ AIModel, Completion, CompletionChunkObject, CompletionResult, ExecutionOptions,
8
+ ExecutionTokenUsage, getMaxTokensLimitVertexAi, JSONObject, JSONSchema, ModelType, PromptOptions, PromptRole,
9
+ PromptSegment, readStreamAsBase64, StatelessExecutionOptions, ToolDefinition, ToolUse,
10
+ VertexAIGeminiOptions
10
11
  } from "@llumiverse/core";
11
12
  import { asyncMap } from "@llumiverse/core/async";
12
13
  import { VertexAIDriver, GenerateContentPrompt } from "../index.js";
@@ -45,42 +46,63 @@ const geminiSafetySettings: SafetySetting[] = [
45
46
  ];
46
47
 
47
48
  function getGeminiPayload(options: ExecutionOptions, prompt: GenerateContentPrompt): GenerateContentParameters {
48
- const model_options = options.model_options as any;
49
+ const model_options = options.model_options as VertexAIGeminiOptions | undefined;
49
50
  const tools = getToolDefinitions(options.tools);
50
51
 
51
52
  const useStructuredOutput = supportsStructuredOutput(options) && !tools;
52
53
 
54
+ const thinkingConfigNeeded = model_options?.include_thoughts
55
+ || model_options?.thinking_budget_tokens
56
+ || options.model.includes("gemini-2.5");
57
+
58
+ const configNanoBanana: GenerateContentConfig = {
59
+ systemInstruction: prompt.system,
60
+ safetySettings: geminiSafetySettings,
61
+ responseModalities: [Modality.TEXT, Modality.IMAGE], // This is an error if only Text, and Only Image just gets blank responses.
62
+ candidateCount: 1,
63
+ //Model options
64
+ temperature: model_options?.temperature,
65
+ topP: model_options?.top_p,
66
+ maxOutputTokens: geminiMaxTokens(options),
67
+ stopSequences: model_options?.stop_sequence,
68
+ imageConfig: {
69
+ aspectRatio: model_options?.image_aspect_ratio,
70
+ }
71
+ }
72
+
73
+ const config: GenerateContentConfig = {
74
+ systemInstruction: prompt.system,
75
+ safetySettings: geminiSafetySettings,
76
+ tools: tools ? [tools] : undefined,
77
+ toolConfig: tools ? {
78
+ functionCallingConfig: {
79
+ mode: FunctionCallingConfigMode.AUTO,
80
+ }
81
+ } : undefined,
82
+ candidateCount: 1,
83
+ //JSON/Structured output
84
+ responseMimeType: useStructuredOutput ? "application/json" : undefined,
85
+ responseSchema: useStructuredOutput ? parseJSONtoSchema(options.result_schema, true) : undefined,
86
+ //Model options
87
+ temperature: model_options?.temperature,
88
+ topP: model_options?.top_p,
89
+ topK: model_options?.top_k,
90
+ maxOutputTokens: geminiMaxTokens(options),
91
+ stopSequences: model_options?.stop_sequence,
92
+ presencePenalty: model_options?.presence_penalty,
93
+ frequencyPenalty: model_options?.frequency_penalty,
94
+ seed: model_options?.seed,
95
+ thinkingConfig: thinkingConfigNeeded ?
96
+ {
97
+ includeThoughts: model_options?.include_thoughts ?? false,
98
+ thinkingBudget: geminiThinkingBudget(options),
99
+ } : undefined,
100
+ }
101
+
53
102
  return {
54
103
  model: options.model,
55
104
  contents: prompt.contents,
56
- config: {
57
- systemInstruction: prompt.system,
58
- safetySettings: geminiSafetySettings,
59
- tools: tools ? [tools] : undefined,
60
- toolConfig: tools ? {
61
- functionCallingConfig: {
62
- mode: FunctionCallingConfigMode.AUTO,
63
- }
64
- } : undefined,
65
- candidateCount: 1,
66
- //JSON/Structured output
67
- responseMimeType: useStructuredOutput ? "application/json" : undefined,
68
- responseSchema: useStructuredOutput ? parseJSONtoSchema(options.result_schema, true) : undefined,
69
- //Model options
70
- temperature: model_options?.temperature,
71
- topP: model_options?.top_p,
72
- topK: model_options?.top_k,
73
- maxOutputTokens: model_options?.max_tokens,
74
- stopSequences: model_options?.stop_sequence,
75
- presencePenalty: model_options?.presence_penalty,
76
- frequencyPenalty: model_options?.frequency_penalty,
77
- seed: model_options?.seed,
78
- thinkingConfig: model_options?.include_thoughts || model_options?.thinking_budget_tokens ?
79
- {
80
- includeThoughts: model_options?.include_thoughts,
81
- thinkingBudget: model_options?.thinking_budget_tokens,
82
- } : undefined,
83
- }
105
+ config: options.model.toLowerCase().includes("image") ? configNanoBanana : config,
84
106
  };
85
107
  }
86
108
 
@@ -336,7 +358,7 @@ function cleanEmptyFieldsContent(content: Content, result_schema?: JSONSchema):
336
358
  const jsonText = JSON.parse(part.text);
337
359
  // Skip cleaning if not an object
338
360
  if (typeof jsonText === 'object' && jsonText !== null && !Array.isArray(jsonText)) {
339
- const cleanedJson = removeEmptyFields(jsonText, result_schema);
361
+ const cleanedJson = removeEmptyFields(jsonText, result_schema);
340
362
  newPart.text = JSON.stringify(cleanedJson);
341
363
  } else {
342
364
  // Keep original if not an object (string, number, array, etc.)
@@ -371,14 +393,14 @@ function removeEmptyFields(object: JSONObject | any[], schema: JSONSchema): JSON
371
393
  if (typeof object == 'object' || object === null) {
372
394
  return removeEmptyJSONObject(object, schema);
373
395
  }
374
-
396
+
375
397
  return object;
376
398
  }
377
399
 
378
400
  function removeEmptyJSONObject(object: JSONObject, schema: JSONSchema): JSONObject {
379
401
  // Get the original required properties from schema
380
402
  const requiredProps = schema.required || [];
381
- const cleanedResult: JSONObject = {...object};
403
+ const cleanedResult: JSONObject = { ...object };
382
404
 
383
405
  // Process each property
384
406
  for (const [key, value] of Object.entries(object)) {
@@ -402,24 +424,46 @@ function removeEmptyJSONObject(object: JSONObject, schema: JSONSchema): JSONObje
402
424
 
403
425
  function removeEmptyJSONArray(array: any[], schema: JSONSchema): any[] {
404
426
  const cleanedArray = array.map(item => {
405
- return removeEmptyFields(item, schema);
427
+ return removeEmptyFields(item, schema);
406
428
  });
407
429
 
408
430
  // Filter out empty objects from the array
409
431
  return cleanedArray.filter(item => !isEmpty(item));
410
432
  }
411
433
 
412
- function collectTextParts(content: Content) {
413
- const out = [];
434
+ function collectTextParts(content: Content): CompletionResult[] {
435
+ const results: CompletionResult[] = [];
414
436
  const parts = content.parts;
415
437
  if (parts) {
416
438
  for (const part of parts) {
417
439
  if (part.text) {
418
- out.push(part.text);
440
+ results.push({
441
+ type: "text",
442
+ value: part.text
443
+ });
419
444
  }
420
445
  }
421
446
  }
422
- return out.join('\n');
447
+ return results;
448
+ }
449
+
450
+ function collectInlineDataParts(content: Content): CompletionResult[] {
451
+ const results: CompletionResult[] = [];
452
+ const parts = content.parts;
453
+ if (parts) {
454
+ for (const part of parts) {
455
+ if (part.inlineData) {
456
+ const base64ImageBytes: string = part.inlineData.data ?? "";
457
+ const mimeType = part.inlineData.mimeType ?? "image/png";
458
+ const imageUrl = `data:${mimeType};base64,${base64ImageBytes}`;
459
+ results.push({
460
+ type: "image",
461
+ value: imageUrl
462
+ });
463
+ }
464
+ }
465
+ }
466
+ return results;
423
467
  }
424
468
 
425
469
  function collectToolUseParts(content: Content): ToolUse[] | undefined {
@@ -440,7 +484,7 @@ function collectToolUseParts(content: Content): ToolUse[] | undefined {
440
484
  export function mergeConsecutiveRole(contents: Content[] | undefined): Content[] {
441
485
  if (!contents || contents.length === 0) return [];
442
486
 
443
- const needsMerging = contents.some((content, i) =>
487
+ const needsMerging = contents.some((content, i) =>
444
488
  i < contents.length - 1 && content.role === contents[i + 1].role
445
489
  );
446
490
  // If no merging needed, return original array
@@ -469,9 +513,38 @@ export function mergeConsecutiveRole(contents: Content[] | undefined): Content[]
469
513
  const supportedFinishReasons: FinishReason[] = [
470
514
  FinishReason.MAX_TOKENS,
471
515
  FinishReason.STOP,
472
- FinishReason.FINISH_REASON_UNSPECIFIED
516
+ FinishReason.FINISH_REASON_UNSPECIFIED,
473
517
  ]
474
518
 
519
+ function geminiMaxTokens(option: StatelessExecutionOptions) {
520
+ const model_options = option.model_options as VertexAIGeminiOptions | undefined;
521
+ if (model_options?.max_tokens) {
522
+ return model_options.max_tokens;
523
+ }
524
+ if (option.model.includes("gemini-2.5")) {
525
+ const maxSupportedTokens = getMaxTokensLimitVertexAi(option.model);
526
+ const thinkingBudget = geminiThinkingBudget(option) ?? 0;
527
+ return Math.min(maxSupportedTokens, 16000 + thinkingBudget);
528
+ }
529
+ return undefined;
530
+ }
531
+
532
+ function geminiThinkingBudget(option: StatelessExecutionOptions) {
533
+ const model_options = option.model_options as VertexAIGeminiOptions | undefined;
534
+ if (model_options?.thinking_budget_tokens) {
535
+ return model_options.thinking_budget_tokens;
536
+ }
537
+ // Set minimum thinking level by default.
538
+ // Docs: https://ai.google.dev/gemini-api/docs/thinking#set-budget
539
+ if (option.model.includes("gemini-2.5")) {
540
+ if (option.model.includes("pro")) {
541
+ return 128;
542
+ }
543
+ return 0;
544
+ }
545
+ return undefined;
546
+ }
547
+
475
548
  export class GeminiModelDefinition implements ModelDefinition<GenerateContentPrompt> {
476
549
 
477
550
  model: AIModel
@@ -492,8 +565,16 @@ export class GeminiModelDefinition implements ModelDefinition<GenerateContentPro
492
565
  return { result, options };
493
566
  }
494
567
  try {
495
- const jsonResult = JSON.parse(result.result);
496
- result.result = JSON.stringify(removeEmptyFields(jsonResult, options.result_schema));
568
+ // Extract text content for JSON processing - only process first text result
569
+ const textResult = result.result.find(r => r.type === 'text')?.value;
570
+ if (textResult) {
571
+ const jsonResult = JSON.parse(textResult);
572
+ const cleanedJson = JSON.stringify(removeEmptyFields(jsonResult, options.result_schema));
573
+ // Replace the text result with cleaned version
574
+ result.result = result.result.map(r =>
575
+ r.type === 'text' ? { ...r, value: cleanedJson } : r
576
+ );
577
+ }
497
578
  return { result, options };
498
579
  } catch (error) {
499
580
  // Log error during processing but don't fail the completion
@@ -511,7 +592,7 @@ export class GeminiModelDefinition implements ModelDefinition<GenerateContentPro
511
592
  const schema = options.result_schema;
512
593
  let contents: Content[] = [];
513
594
  let system: Content | undefined = { role: "user", parts: [] }; // Single content block for system messages
514
-
595
+
515
596
  const safety: Content[] = [];
516
597
 
517
598
  for (const msg of segments) {
@@ -524,7 +605,7 @@ export class GeminiModelDefinition implements ModelDefinition<GenerateContentPro
524
605
 
525
606
  if (msg.content) {
526
607
  system.parts?.push({
527
- text: msg.content
608
+ text: msg.content
528
609
  });
529
610
  }
530
611
  } else if (msg.role === PromptRole.tool) {
@@ -598,7 +679,7 @@ export class GeminiModelDefinition implements ModelDefinition<GenerateContentPro
598
679
  }
599
680
  }
600
681
  }
601
-
682
+
602
683
  // If no system messages, set system to undefined.
603
684
  if (!system.parts || system.parts.length === 0) {
604
685
  system = undefined;
@@ -611,7 +692,7 @@ export class GeminiModelDefinition implements ModelDefinition<GenerateContentPro
611
692
 
612
693
  // Merge consecutive messages with the same role. Note: this may not be necessary, works without it, keeping to match previous behavior.
613
694
  contents = mergeConsecutiveRole(contents);
614
-
695
+
615
696
  return { contents, system };
616
697
  }
617
698
 
@@ -625,7 +706,7 @@ export class GeminiModelDefinition implements ModelDefinition<GenerateContentPro
625
706
  tokenUsage.result = (usageMetadata.candidatesTokenCount ?? 0)
626
707
  + (usageMetadata.thoughtsTokenCount ?? 0)
627
708
  + (usageMetadata.toolUsePromptTokenCount ?? 0);
628
-
709
+
629
710
  if ((tokenUsage.total ?? 0) != (tokenUsage.prompt ?? 0) + tokenUsage.result) {
630
711
  console.warn("[VertexAI] Gemini token usage mismatch: total does not equal prompt + result", {
631
712
  total: tokenUsage.total,
@@ -633,7 +714,7 @@ export class GeminiModelDefinition implements ModelDefinition<GenerateContentPro
633
714
  result: tokenUsage.result
634
715
  });
635
716
  }
636
-
717
+
637
718
  if (!tokenUsage.result) {
638
719
  tokenUsage.result = undefined; // If no result, mark as undefined
639
720
  }
@@ -643,13 +724,21 @@ export class GeminiModelDefinition implements ModelDefinition<GenerateContentPro
643
724
 
644
725
  async requestTextCompletion(driver: VertexAIDriver, prompt: GenerateContentPrompt, options: ExecutionOptions): Promise<Completion> {
645
726
  const splits = options.model.split("/");
727
+ let region: string | undefined = undefined;
728
+ if (splits[0] === "locations" && splits.length >= 2) {
729
+ region = splits[1];
730
+ }
646
731
  const modelName = splits[splits.length - 1];
647
732
  options = { ...options, model: modelName };
648
733
 
649
734
  let conversation = updateConversation(options.conversation as Content[], prompt.contents);
650
735
  prompt.contents = conversation;
651
736
 
652
- const client = driver.getGoogleGenAIClient();
737
+ if (options.model.includes("gemini-2.5-flash-image")) {
738
+ region = "global"; // Gemini Flash Image only available in global region, this is for nano-banana model
739
+ }
740
+
741
+ const client = driver.getGoogleGenAIClient(region);
653
742
 
654
743
  const payload = getGeminiPayload(options, prompt);
655
744
  const response = await client.models.generateContent(payload);
@@ -678,19 +767,21 @@ export class GeminiModelDefinition implements ModelDefinition<GenerateContentPro
678
767
 
679
768
  // We clean the content before validation, so we can update the conversation.
680
769
  const cleanedContent = cleanEmptyFieldsContent(content, options.result_schema);
681
- result = collectTextParts(cleanedContent);
770
+ const textResults = collectTextParts(cleanedContent);
771
+ const imageResults = collectInlineDataParts(cleanedContent);
772
+ result = [...textResults, ...imageResults];
682
773
  conversation = updateConversation(conversation, [cleanedContent]);
683
774
  }
684
775
  }
685
776
 
686
-
777
+
687
778
 
688
779
  if (tool_use) {
689
780
  finish_reason = "tool_use";
690
781
  }
691
782
 
692
783
  return {
693
- result: result ?? '',
784
+ result: result && result.length > 0 ? result : [{ type: "text" as const, value: '' }],
694
785
  token_usage: token_usage,
695
786
  finish_reason: finish_reason,
696
787
  original_response: options.include_original_response ? response : undefined,
@@ -701,10 +792,18 @@ export class GeminiModelDefinition implements ModelDefinition<GenerateContentPro
701
792
 
702
793
  async requestTextCompletionStream(driver: VertexAIDriver, prompt: GenerateContentPrompt, options: ExecutionOptions): Promise<AsyncIterable<CompletionChunkObject>> {
703
794
  const splits = options.model.split("/");
795
+ let region: string | undefined = undefined;
796
+ if (splits[0] === "locations" && splits.length >= 2) {
797
+ region = splits[1];
798
+ }
704
799
  const modelName = splits[splits.length - 1];
705
800
  options = { ...options, model: modelName };
706
801
 
707
- const client = driver.getGoogleGenAIClient();
802
+ if (options.model.includes("gemini-2.5-flash-image")) {
803
+ region = "global"; // Gemini Flash Image only available in global region, this is for nano-banana model
804
+ }
805
+
806
+ const client = driver.getGoogleGenAIClient(region);
708
807
 
709
808
  const payload = getGeminiPayload(options, prompt);
710
809
  const response = await client.models.generateContentStream(payload);
@@ -726,13 +825,15 @@ export class GeminiModelDefinition implements ModelDefinition<GenerateContentPro
726
825
  + `content: ${JSON.stringify(candidate.content, null, 2)}, safety: ${JSON.stringify(candidate.safetyRatings, null, 2)}`);
727
826
  }
728
827
  if (candidate.content?.role === 'model') {
729
- const text = collectTextParts(candidate.content);
828
+ const textResults = collectTextParts(candidate.content);
829
+ const imageResults = collectInlineDataParts(candidate.content);
830
+ const combinedResults = [...textResults, ...imageResults];
730
831
  tool_use = collectToolUseParts(candidate.content);
731
832
  if (tool_use) {
732
833
  finish_reason = "tool_use";
733
834
  }
734
835
  return {
735
- result: text,
836
+ result: combinedResults.length > 0 ? combinedResults : [],
736
837
  token_usage: token_usage,
737
838
  finish_reason: finish_reason,
738
839
  tool_use,
@@ -742,7 +843,7 @@ export class GeminiModelDefinition implements ModelDefinition<GenerateContentPro
742
843
  }
743
844
  //No normal output, returning block reason if it exists.
744
845
  return {
745
- result: item.promptFeedback?.blockReasonMessage ?? "",
846
+ result: item.promptFeedback?.blockReasonMessage ? [{ type: "text" as const, value: item.promptFeedback.blockReasonMessage }] : [],
746
847
  finish_reason: item.promptFeedback?.blockReason ?? "",
747
848
  token_usage: token_usage,
748
849
  };
@@ -1,19 +1,12 @@
1
1
  import {
2
- AIModel, Completion, ExecutionOptions, ImageGeneration, Modalities,
2
+ AIModel, Completion, ExecutionOptions, Modalities,
3
3
  ModelType, PromptRole, PromptSegment, readStreamAsBase64, ImagenOptions
4
4
  } from "@llumiverse/core";
5
5
  import { VertexAIDriver } from "../index.js";
6
6
 
7
- const projectId = process.env.GOOGLE_PROJECT_ID;
8
- const location = 'us-central1';
9
-
10
- import aiplatform, { protos } from '@google-cloud/aiplatform';
11
-
12
- // Imports the Google Cloud Prediction Service Client library
13
- const { PredictionServiceClient } = aiplatform.v1;
14
-
15
7
  // Import the helper module for converting arbitrary protobuf.Value objects
16
- import { helpers } from '@google-cloud/aiplatform';
8
+ import { protos, helpers } from '@google-cloud/aiplatform';
9
+
17
10
  interface ImagenBaseReference {
18
11
  referenceType: "REFERENCE_TYPE_RAW" | "REFERENCE_TYPE_MASK" | "REFERENCE_TYPE_SUBJECT" |
19
12
  "REFERENCE_TYPE_CONTROL" | "REFERENCE_TYPE_STYLE";
@@ -90,14 +83,6 @@ export interface ImagenPrompt {
90
83
  negativePrompt?: string; //Used for negative prompts
91
84
  }
92
85
 
93
- // Specifies the location of the api endpoint
94
- const clientOptions = {
95
- apiEndpoint: `${location}-aiplatform.googleapis.com`,
96
- };
97
-
98
- // Instantiates a client
99
- const predictionServiceClient = new PredictionServiceClient(clientOptions);
100
-
101
86
  function getImagenParameters(taskType: string, options: ImagenOptions) {
102
87
  const commonParameters = {
103
88
  sampleCount: options?.number_of_images,
@@ -337,9 +322,9 @@ export class ImagenModelDefinition {
337
322
  return prompt
338
323
  }
339
324
 
340
- async requestImageGeneration(driver: VertexAIDriver, prompt: ImagenPrompt, options: ExecutionOptions): Promise<Completion<ImageGeneration>> {
325
+ async requestImageGeneration(driver: VertexAIDriver, prompt: ImagenPrompt, options: ExecutionOptions): Promise<Completion> {
341
326
  if (options.model_options?._option_id !== "vertexai-imagen") {
342
- driver.logger.warn("Invalid model options", {options: options.model_options });
327
+ driver.logger.warn({ options: options.model_options }, "Invalid model options");
343
328
  }
344
329
  options.model_options = options.model_options as ImagenOptions | undefined;
345
330
 
@@ -354,7 +339,8 @@ export class ImagenModelDefinition {
354
339
  const modelName = options.model.split("/").pop() ?? '';
355
340
 
356
341
  // Configure the parent resource
357
- const endpoint = `projects/${projectId}/locations/${location}/publishers/google/models/${modelName}`;
342
+ // TODO: make location configurable, fixed to us-central1 for now
343
+ const endpoint = `projects/${driver.options.project}/locations/us-central1/publishers/google/models/${modelName}`;
358
344
 
359
345
  const instanceValue = helpers.toValue(prompt);
360
346
  if (!instanceValue) {
@@ -362,7 +348,7 @@ export class ImagenModelDefinition {
362
348
  }
363
349
  const instances = [instanceValue];
364
350
 
365
- let parameter: any = getImagenParameters(taskType, options.model_options ?? {_option_id: "vertexai-imagen"});
351
+ let parameter: any = getImagenParameters(taskType, options.model_options ?? { _option_id: "vertexai-imagen" });
366
352
  parameter.negativePrompt = prompt.negativePrompt ?? undefined;
367
353
 
368
354
  const numberOfImages = options.model_options?.number_of_images ?? 1;
@@ -380,8 +366,10 @@ export class ImagenModelDefinition {
380
366
  parameters,
381
367
  };
382
368
 
369
+ const client = await driver.getImagenClient();
370
+
383
371
  // Predict request
384
- const [response] = await predictionServiceClient.predict(request, { timeout: 120000 * numberOfImages }); //Extended timeout for image generation
372
+ const [response] = await client.predict(request, { timeout: 120000 * numberOfImages }); //Extended timeout for image generation
385
373
  const predictions = response.predictions;
386
374
 
387
375
  if (!predictions) {
@@ -394,9 +382,10 @@ export class ImagenModelDefinition {
394
382
  );
395
383
 
396
384
  return {
397
- result: {
398
- images
399
- },
385
+ result: images.map(image => ({
386
+ type: "image" as const,
387
+ value: image
388
+ })),
400
389
  };
401
390
  }
402
391
  }