@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.
- package/README.md +1 -1
- package/lib/cjs/adobe/firefly.js +8 -7
- package/lib/cjs/adobe/firefly.js.map +1 -1
- package/lib/cjs/azure/azure_foundry.js +12 -12
- package/lib/cjs/azure/azure_foundry.js.map +1 -1
- package/lib/cjs/bedrock/index.js +172 -22
- package/lib/cjs/bedrock/index.js.map +1 -1
- package/lib/cjs/bedrock/twelvelabs.js +87 -0
- package/lib/cjs/bedrock/twelvelabs.js.map +1 -0
- package/lib/cjs/groq/index.js +91 -16
- package/lib/cjs/groq/index.js.map +1 -1
- package/lib/cjs/huggingface_ie.js +7 -6
- package/lib/cjs/huggingface_ie.js.map +1 -1
- package/lib/cjs/index.js +2 -2
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/mistral/index.js +5 -4
- package/lib/cjs/mistral/index.js.map +1 -1
- package/lib/cjs/openai/azure_openai.js +1 -1
- package/lib/cjs/openai/azure_openai.js.map +1 -1
- package/lib/cjs/openai/index.js +16 -12
- package/lib/cjs/openai/index.js.map +1 -1
- package/lib/cjs/replicate.js +6 -6
- package/lib/cjs/replicate.js.map +1 -1
- package/lib/cjs/test/utils.js +1 -1
- package/lib/cjs/test/utils.js.map +1 -1
- package/lib/cjs/test-driver/TestErrorCompletionStream.js +20 -0
- package/lib/cjs/test-driver/TestErrorCompletionStream.js.map +1 -0
- package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js +24 -0
- package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js.map +1 -0
- package/lib/cjs/test-driver/index.js +109 -0
- package/lib/cjs/test-driver/index.js.map +1 -0
- package/lib/cjs/test-driver/utils.js +30 -0
- package/lib/cjs/test-driver/utils.js.map +1 -0
- package/lib/cjs/togetherai/index.js +4 -4
- package/lib/cjs/togetherai/index.js.map +1 -1
- package/lib/cjs/vertexai/embeddings/embeddings-text.js +1 -1
- package/lib/cjs/vertexai/embeddings/embeddings-text.js.map +1 -1
- package/lib/cjs/vertexai/index.js +136 -31
- package/lib/cjs/vertexai/index.js.map +1 -1
- package/lib/cjs/vertexai/models/claude.js +38 -16
- package/lib/cjs/vertexai/models/claude.js.map +1 -1
- package/lib/cjs/vertexai/models/gemini.js +131 -41
- package/lib/cjs/vertexai/models/gemini.js.map +1 -1
- package/lib/cjs/vertexai/models/imagen.js +12 -23
- package/lib/cjs/vertexai/models/imagen.js.map +1 -1
- package/lib/cjs/vertexai/models/llama.js +4 -3
- package/lib/cjs/vertexai/models/llama.js.map +1 -1
- package/lib/cjs/vertexai/models.js +13 -2
- package/lib/cjs/vertexai/models.js.map +1 -1
- package/lib/cjs/watsonx/index.js +5 -5
- package/lib/cjs/watsonx/index.js.map +1 -1
- package/lib/cjs/xai/index.js +1 -1
- package/lib/cjs/xai/index.js.map +1 -1
- package/lib/esm/adobe/firefly.js +8 -7
- package/lib/esm/adobe/firefly.js.map +1 -1
- package/lib/esm/azure/azure_foundry.js +12 -12
- package/lib/esm/azure/azure_foundry.js.map +1 -1
- package/lib/esm/bedrock/index.js +172 -22
- package/lib/esm/bedrock/index.js.map +1 -1
- package/lib/esm/bedrock/twelvelabs.js +84 -0
- package/lib/esm/bedrock/twelvelabs.js.map +1 -0
- package/lib/esm/groq/index.js +91 -16
- package/lib/esm/groq/index.js.map +1 -1
- package/lib/esm/huggingface_ie.js +8 -7
- package/lib/esm/huggingface_ie.js.map +1 -1
- package/lib/esm/index.js +2 -2
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/mistral/index.js +5 -4
- package/lib/esm/mistral/index.js.map +1 -1
- package/lib/esm/openai/azure_openai.js +1 -1
- package/lib/esm/openai/azure_openai.js.map +1 -1
- package/lib/esm/openai/index.js +16 -12
- package/lib/esm/openai/index.js.map +1 -1
- package/lib/esm/replicate.js +6 -6
- package/lib/esm/replicate.js.map +1 -1
- package/lib/esm/src/adobe/firefly.js +116 -0
- package/lib/esm/src/adobe/firefly.js.map +1 -0
- package/lib/esm/src/azure/azure_foundry.js +382 -0
- package/lib/esm/src/azure/azure_foundry.js.map +1 -0
- package/lib/esm/src/bedrock/converse.js +278 -0
- package/lib/esm/src/bedrock/converse.js.map +1 -0
- package/lib/esm/src/bedrock/index.js +962 -0
- package/lib/esm/src/bedrock/index.js.map +1 -0
- package/lib/esm/src/bedrock/nova-image-payload.js +203 -0
- package/lib/esm/src/bedrock/nova-image-payload.js.map +1 -0
- package/lib/esm/src/bedrock/payloads.js +2 -0
- package/lib/esm/src/bedrock/payloads.js.map +1 -0
- package/lib/esm/src/bedrock/s3.js +99 -0
- package/lib/esm/src/bedrock/s3.js.map +1 -0
- package/lib/esm/src/bedrock/twelvelabs.js +84 -0
- package/lib/esm/src/bedrock/twelvelabs.js.map +1 -0
- package/lib/esm/src/groq/index.js +286 -0
- package/lib/esm/src/groq/index.js.map +1 -0
- package/lib/esm/src/huggingface_ie.js +197 -0
- package/lib/esm/src/huggingface_ie.js.map +1 -0
- package/lib/esm/src/index.js +14 -0
- package/lib/esm/src/index.js.map +1 -0
- package/lib/esm/src/mistral/index.js +169 -0
- package/lib/esm/src/mistral/index.js.map +1 -0
- package/lib/esm/src/mistral/types.js +80 -0
- package/lib/esm/src/mistral/types.js.map +1 -0
- package/lib/esm/src/openai/azure_openai.js +68 -0
- package/lib/esm/src/openai/azure_openai.js.map +1 -0
- package/lib/esm/src/openai/index.js +464 -0
- package/lib/esm/src/openai/index.js.map +1 -0
- package/lib/esm/src/openai/openai.js +14 -0
- package/lib/esm/src/openai/openai.js.map +1 -0
- package/lib/esm/src/openai/openai_format.js +134 -0
- package/lib/esm/src/openai/openai_format.js.map +1 -0
- package/lib/esm/src/replicate.js +268 -0
- package/lib/esm/src/replicate.js.map +1 -0
- package/lib/esm/src/test/TestErrorCompletionStream.js +16 -0
- package/lib/esm/src/test/TestErrorCompletionStream.js.map +1 -0
- package/lib/esm/src/test/TestValidationErrorCompletionStream.js +20 -0
- package/lib/esm/src/test/TestValidationErrorCompletionStream.js.map +1 -0
- package/lib/esm/src/test/index.js +91 -0
- package/lib/esm/src/test/index.js.map +1 -0
- package/lib/esm/src/test/utils.js +25 -0
- package/lib/esm/src/test/utils.js.map +1 -0
- package/lib/esm/src/test-driver/TestErrorCompletionStream.js +16 -0
- package/lib/esm/src/test-driver/TestErrorCompletionStream.js.map +1 -0
- package/lib/esm/src/test-driver/TestValidationErrorCompletionStream.js +20 -0
- package/lib/esm/src/test-driver/TestValidationErrorCompletionStream.js.map +1 -0
- package/lib/esm/src/test-driver/index.js +91 -0
- package/lib/esm/src/test-driver/index.js.map +1 -0
- package/lib/esm/src/test-driver/utils.js +25 -0
- package/lib/esm/src/test-driver/utils.js.map +1 -0
- package/lib/esm/src/togetherai/index.js +122 -0
- package/lib/esm/src/togetherai/index.js.map +1 -0
- package/lib/esm/src/togetherai/interfaces.js +2 -0
- package/lib/esm/src/togetherai/interfaces.js.map +1 -0
- package/lib/esm/src/vertexai/debug.js +6 -0
- package/lib/esm/src/vertexai/debug.js.map +1 -0
- package/lib/esm/src/vertexai/embeddings/embeddings-image.js +24 -0
- package/lib/esm/src/vertexai/embeddings/embeddings-image.js.map +1 -0
- package/lib/esm/src/vertexai/embeddings/embeddings-text.js +20 -0
- package/lib/esm/src/vertexai/embeddings/embeddings-text.js.map +1 -0
- package/lib/esm/src/vertexai/index.js +383 -0
- package/lib/esm/src/vertexai/index.js.map +1 -0
- package/lib/esm/src/vertexai/models/claude.js +394 -0
- package/lib/esm/src/vertexai/models/claude.js.map +1 -0
- package/lib/esm/src/vertexai/models/gemini.js +817 -0
- package/lib/esm/src/vertexai/models/gemini.js.map +1 -0
- package/lib/esm/src/vertexai/models/imagen.js +302 -0
- package/lib/esm/src/vertexai/models/imagen.js.map +1 -0
- package/lib/esm/src/vertexai/models/llama.js +179 -0
- package/lib/esm/src/vertexai/models/llama.js.map +1 -0
- package/lib/esm/src/vertexai/models.js +32 -0
- package/lib/esm/src/vertexai/models.js.map +1 -0
- package/lib/esm/src/watsonx/index.js +157 -0
- package/lib/esm/src/watsonx/index.js.map +1 -0
- package/lib/esm/src/watsonx/interfaces.js +2 -0
- package/lib/esm/src/watsonx/interfaces.js.map +1 -0
- package/lib/esm/src/xai/index.js +64 -0
- package/lib/esm/src/xai/index.js.map +1 -0
- package/lib/esm/test/utils.js +1 -1
- package/lib/esm/test/utils.js.map +1 -1
- package/lib/esm/test-driver/TestErrorCompletionStream.js +16 -0
- package/lib/esm/test-driver/TestErrorCompletionStream.js.map +1 -0
- package/lib/esm/test-driver/TestValidationErrorCompletionStream.js +20 -0
- package/lib/esm/test-driver/TestValidationErrorCompletionStream.js.map +1 -0
- package/lib/esm/test-driver/index.js +91 -0
- package/lib/esm/test-driver/index.js.map +1 -0
- package/lib/esm/test-driver/utils.js +25 -0
- package/lib/esm/test-driver/utils.js.map +1 -0
- package/lib/esm/togetherai/index.js +4 -4
- package/lib/esm/togetherai/index.js.map +1 -1
- package/lib/esm/tsconfig.tsbuildinfo +1 -0
- package/lib/esm/vertexai/embeddings/embeddings-text.js +1 -1
- package/lib/esm/vertexai/embeddings/embeddings-text.js.map +1 -1
- package/lib/esm/vertexai/index.js +136 -31
- package/lib/esm/vertexai/index.js.map +1 -1
- package/lib/esm/vertexai/models/claude.js +37 -15
- package/lib/esm/vertexai/models/claude.js.map +1 -1
- package/lib/esm/vertexai/models/gemini.js +133 -43
- package/lib/esm/vertexai/models/gemini.js.map +1 -1
- package/lib/esm/vertexai/models/imagen.js +9 -17
- package/lib/esm/vertexai/models/imagen.js.map +1 -1
- package/lib/esm/vertexai/models/llama.js +4 -3
- package/lib/esm/vertexai/models/llama.js.map +1 -1
- package/lib/esm/vertexai/models.js +13 -2
- package/lib/esm/vertexai/models.js.map +1 -1
- package/lib/esm/watsonx/index.js +5 -5
- package/lib/esm/watsonx/index.js.map +1 -1
- package/lib/esm/xai/index.js +1 -1
- package/lib/esm/xai/index.js.map +1 -1
- package/lib/types/adobe/firefly.d.ts +3 -3
- package/lib/types/adobe/firefly.d.ts.map +1 -1
- package/lib/types/azure/azure_foundry.d.ts +2 -2
- package/lib/types/azure/azure_foundry.d.ts.map +1 -1
- package/lib/types/bedrock/index.d.ts +9 -5
- package/lib/types/bedrock/index.d.ts.map +1 -1
- package/lib/types/bedrock/twelvelabs.d.ts +50 -0
- package/lib/types/bedrock/twelvelabs.d.ts.map +1 -0
- package/lib/types/groq/index.d.ts +3 -0
- package/lib/types/groq/index.d.ts.map +1 -1
- package/lib/types/huggingface_ie.d.ts +8 -5
- package/lib/types/huggingface_ie.d.ts.map +1 -1
- package/lib/types/index.d.ts +2 -2
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/mistral/index.d.ts +2 -2
- package/lib/types/mistral/index.d.ts.map +1 -1
- package/lib/types/openai/index.d.ts +2 -2
- package/lib/types/openai/index.d.ts.map +1 -1
- package/lib/types/replicate.d.ts +6 -3
- package/lib/types/replicate.d.ts.map +1 -1
- package/lib/types/src/adobe/firefly.d.ts +29 -0
- package/lib/types/src/azure/azure_foundry.d.ts +49 -0
- package/lib/types/src/bedrock/converse.d.ts +8 -0
- package/lib/types/src/bedrock/index.d.ts +61 -0
- package/lib/types/src/bedrock/nova-image-payload.d.ts +73 -0
- package/lib/types/src/bedrock/payloads.d.ts +11 -0
- package/lib/types/src/bedrock/s3.d.ts +22 -0
- package/lib/types/src/bedrock/twelvelabs.d.ts +49 -0
- package/lib/types/src/groq/index.d.ts +26 -0
- package/lib/types/src/huggingface_ie.d.ts +34 -0
- package/lib/types/src/index.d.ts +13 -0
- package/lib/types/src/mistral/index.d.ts +24 -0
- package/lib/types/src/mistral/types.d.ts +131 -0
- package/lib/types/src/openai/azure_openai.d.ts +24 -0
- package/lib/types/src/openai/index.d.ts +24 -0
- package/lib/types/src/openai/openai.d.ts +14 -0
- package/lib/types/src/openai/openai_format.d.ts +18 -0
- package/lib/types/src/replicate.d.ts +47 -0
- package/lib/types/src/test/TestErrorCompletionStream.d.ts +8 -0
- package/lib/types/src/test/TestValidationErrorCompletionStream.d.ts +8 -0
- package/lib/types/src/test/index.d.ts +23 -0
- package/lib/types/src/test/utils.d.ts +4 -0
- package/lib/types/src/test-driver/TestErrorCompletionStream.d.ts +8 -0
- package/lib/types/src/test-driver/TestValidationErrorCompletionStream.d.ts +8 -0
- package/lib/types/src/test-driver/index.d.ts +23 -0
- package/lib/types/src/test-driver/utils.d.ts +4 -0
- package/lib/types/src/togetherai/index.d.ts +22 -0
- package/lib/types/src/togetherai/interfaces.d.ts +95 -0
- package/lib/types/src/vertexai/debug.d.ts +1 -0
- package/lib/types/src/vertexai/embeddings/embeddings-image.d.ts +10 -0
- package/lib/types/src/vertexai/embeddings/embeddings-text.d.ts +9 -0
- package/lib/types/src/vertexai/index.d.ts +52 -0
- package/lib/types/src/vertexai/models/claude.d.ts +19 -0
- package/lib/types/src/vertexai/models/gemini.d.ts +17 -0
- package/lib/types/src/vertexai/models/imagen.d.ts +74 -0
- package/lib/types/src/vertexai/models/llama.d.ts +19 -0
- package/lib/types/src/vertexai/models.d.ts +14 -0
- package/lib/types/src/watsonx/index.d.ts +26 -0
- package/lib/types/src/watsonx/interfaces.d.ts +64 -0
- package/lib/types/src/xai/index.d.ts +18 -0
- package/lib/types/test-driver/TestErrorCompletionStream.d.ts +9 -0
- package/lib/types/test-driver/TestErrorCompletionStream.d.ts.map +1 -0
- package/lib/types/test-driver/TestValidationErrorCompletionStream.d.ts +9 -0
- package/lib/types/test-driver/TestValidationErrorCompletionStream.d.ts.map +1 -0
- package/lib/types/test-driver/index.d.ts +24 -0
- package/lib/types/test-driver/index.d.ts.map +1 -0
- package/lib/types/test-driver/utils.d.ts +5 -0
- package/lib/types/test-driver/utils.d.ts.map +1 -0
- package/lib/types/togetherai/index.d.ts +3 -3
- package/lib/types/togetherai/index.d.ts.map +1 -1
- package/lib/types/vertexai/index.d.ts +17 -14
- package/lib/types/vertexai/index.d.ts.map +1 -1
- package/lib/types/vertexai/models/claude.d.ts +2 -0
- package/lib/types/vertexai/models/claude.d.ts.map +1 -1
- package/lib/types/vertexai/models/gemini.d.ts.map +1 -1
- package/lib/types/vertexai/models/imagen.d.ts +2 -2
- package/lib/types/vertexai/models/imagen.d.ts.map +1 -1
- package/lib/types/vertexai/models/llama.d.ts +2 -2
- package/lib/types/vertexai/models/llama.d.ts.map +1 -1
- package/lib/types/vertexai/models.d.ts +2 -2
- package/lib/types/vertexai/models.d.ts.map +1 -1
- package/lib/types/watsonx/index.d.ts +3 -3
- package/lib/types/watsonx/index.d.ts.map +1 -1
- package/package.json +90 -85
- package/src/adobe/firefly.ts +14 -22
- package/src/azure/azure_foundry.ts +16 -16
- package/src/bedrock/index.ts +207 -28
- package/src/bedrock/twelvelabs.ts +150 -0
- package/src/groq/index.ts +134 -37
- package/src/huggingface_ie.ts +13 -14
- package/src/index.ts +2 -2
- package/src/mistral/index.ts +8 -7
- package/src/openai/azure_openai.ts +5 -5
- package/src/openai/index.ts +19 -13
- package/src/replicate.ts +14 -14
- package/src/{test → test-driver}/utils.ts +1 -1
- package/src/togetherai/index.ts +7 -7
- package/src/vertexai/embeddings/embeddings-text.ts +2 -2
- package/src/vertexai/index.ts +156 -40
- package/src/vertexai/models/claude.ts +45 -19
- package/src/vertexai/models/gemini.ts +161 -60
- package/src/vertexai/models/imagen.ts +15 -26
- package/src/vertexai/models/llama.ts +6 -5
- package/src/vertexai/models.ts +18 -6
- package/src/watsonx/index.ts +8 -8
- package/src/xai/index.ts +11 -12
- /package/src/{test → test-driver}/TestErrorCompletionStream.ts +0 -0
- /package/src/{test → test-driver}/TestValidationErrorCompletionStream.ts +0 -0
- /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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
440
|
+
results.push({
|
|
441
|
+
type: "text",
|
|
442
|
+
value: part.text
|
|
443
|
+
});
|
|
419
444
|
}
|
|
420
445
|
}
|
|
421
446
|
}
|
|
422
|
-
return
|
|
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
|
-
|
|
496
|
-
result.result
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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,
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
399
|
-
|
|
385
|
+
result: images.map(image => ({
|
|
386
|
+
type: "image" as const,
|
|
387
|
+
value: image
|
|
388
|
+
})),
|
|
400
389
|
};
|
|
401
390
|
}
|
|
402
391
|
}
|