@core-ai/google-genai 0.13.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,3 +26,23 @@ const result = await generate({
26
26
 
27
27
  console.log(result.content);
28
28
  ```
29
+
30
+ ## Image generation
31
+
32
+ `imageModel()` supports Gemini native image models and dedicated Imagen models:
33
+
34
+ ```ts
35
+ import { generateImage } from '@core-ai/core-ai';
36
+
37
+ const result = await generateImage({
38
+ model: google.imageModel('gemini-2.5-flash-image'),
39
+ prompt: 'A watercolor robot in a mountain cabin at sunrise',
40
+ size: '1024x1024',
41
+ });
42
+
43
+ console.log(result.images[0]?.base64);
44
+ ```
45
+
46
+ Gemini model IDs use native multimodal generation and return base64 image
47
+ data. Imagen model IDs such as `imagen-4.0-generate-001` use the dedicated
48
+ Imagen API and also support generating multiple images with `n`.
package/dist/index.d.ts CHANGED
@@ -2,17 +2,25 @@ import { GoogleGenAI } from '@google/genai';
2
2
  import { ChatModel, EmbeddingModel, ImageModel, ModelCapabilities } from '@core-ai/core-ai';
3
3
  import { z } from 'zod';
4
4
 
5
- type GoogleGenAIProviderOptions = {
5
+ type GoogleGenAIClient = {
6
+ models: GoogleGenAI['models'];
7
+ };
8
+ type GoogleGenAIProviderBaseOptions = {
6
9
  apiKey?: string;
7
10
  apiVersion?: string;
8
11
  baseUrl?: string;
9
- client?: GoogleGenAI;
12
+ client?: GoogleGenAIClient;
13
+ };
14
+ type GoogleGenAIProviderFactoryOptions = {
15
+ providerId?: string;
10
16
  };
17
+ type GoogleGenAIProviderOptions = GoogleGenAIProviderBaseOptions;
11
18
  type GoogleGenAIProvider = {
12
19
  chatModel(modelId: string): ChatModel;
13
20
  embeddingModel(modelId: string): EmbeddingModel;
14
21
  imageModel(modelId: string): ImageModel;
15
22
  };
23
+ declare function createGoogleGenAIProvider(options?: GoogleGenAIProviderBaseOptions, factoryOptions?: GoogleGenAIProviderFactoryOptions): GoogleGenAIProvider;
16
24
  declare function createGoogleGenAI(options?: GoogleGenAIProviderOptions): GoogleGenAIProvider;
17
25
 
18
26
  type GoogleReasoningMetadata = {
@@ -90,4 +98,4 @@ declare const googleProviderOptionsSchema: z.ZodObject<{
90
98
  }, z.core.$strict>;
91
99
  type GoogleProviderOptions = GoogleGenerateProviderOptions;
92
100
 
93
- export { type GoogleEmbedProviderOptions, type GoogleGenAIProvider, type GoogleGenAIProviderOptions, type GoogleGenerateProviderOptions, type GoogleImageProviderOptions, type GoogleModelCapabilities, type GoogleProviderOptions as GoogleModelProviderOptions, type GoogleReasoningMetadata, createGoogleGenAI, getGoogleModelCapabilities, googleEmbedProviderOptionsSchema, googleGenerateProviderOptionsSchema, googleImageProviderOptionsSchema, googleProviderOptionsSchema };
101
+ export { type GoogleEmbedProviderOptions, type GoogleGenAIClient, type GoogleGenAIProvider, type GoogleGenAIProviderBaseOptions, type GoogleGenAIProviderFactoryOptions, type GoogleGenAIProviderOptions, type GoogleGenerateProviderOptions, type GoogleImageProviderOptions, type GoogleModelCapabilities, type GoogleProviderOptions as GoogleModelProviderOptions, type GoogleReasoningMetadata, createGoogleGenAI, createGoogleGenAIProvider, getGoogleModelCapabilities, googleEmbedProviderOptionsSchema, googleGenerateProviderOptionsSchema, googleImageProviderOptionsSchema, googleProviderOptionsSchema };
package/dist/index.js CHANGED
@@ -439,6 +439,7 @@ async function* transformStream(stream) {
439
439
  const bufferedToolCalls = /* @__PURE__ */ new Map();
440
440
  let finishReason = "unknown";
441
441
  let sawToolCalls = false;
442
+ let textOpen = false;
442
443
  let reasoningOpen = false;
443
444
  let usage = {
444
445
  inputTokens: 0,
@@ -459,10 +460,25 @@ async function* transformStream(stream) {
459
460
  providerMetadata: { google: {} }
460
461
  };
461
462
  };
463
+ const startText = function* () {
464
+ if (textOpen) {
465
+ return;
466
+ }
467
+ textOpen = true;
468
+ yield { type: "text-start" };
469
+ };
470
+ const closeText = function* () {
471
+ if (!textOpen) {
472
+ return;
473
+ }
474
+ textOpen = false;
475
+ yield { type: "text-end" };
476
+ };
462
477
  for await (const chunk of stream) {
463
478
  usage = mapUsage(chunk, usage);
464
479
  const reasoningDeltas = extractReasoningDeltas(chunk);
465
480
  if (reasoningDeltas.length > 0) {
481
+ yield* closeText();
466
482
  if (!reasoningOpen) {
467
483
  reasoningOpen = true;
468
484
  yield {
@@ -481,6 +497,7 @@ async function* transformStream(stream) {
481
497
  if (reasoningEnd2) {
482
498
  yield reasoningEnd2;
483
499
  }
500
+ yield* startText();
484
501
  yield {
485
502
  type: "text-delta",
486
503
  text: chunk.text
@@ -488,6 +505,7 @@ async function* transformStream(stream) {
488
505
  }
489
506
  const functionCalls = chunk.functionCalls ?? [];
490
507
  if (functionCalls.length > 0) {
508
+ yield* closeText();
491
509
  const reasoningEnd2 = closeReasoning();
492
510
  if (reasoningEnd2) {
493
511
  yield reasoningEnd2;
@@ -538,6 +556,7 @@ async function* transformStream(stream) {
538
556
  if (reasoningEnd) {
539
557
  yield reasoningEnd;
540
558
  }
559
+ yield* closeText();
541
560
  for (const toolCall of bufferedToolCalls.values()) {
542
561
  yield {
543
562
  type: "tool-call-end",
@@ -665,33 +684,32 @@ function mapUsage(response, fallback) {
665
684
  // src/google-error.ts
666
685
  import { ApiError } from "@google/genai";
667
686
  import { ProviderError } from "@core-ai/core-ai";
668
- function wrapGoogleError(error) {
687
+ function wrapGoogleError(error, provider = "google") {
669
688
  if (error instanceof ApiError) {
670
- return new ProviderError(error.message, "google", error.status, error);
689
+ return new ProviderError(error.message, provider, error.status, error);
671
690
  }
672
691
  return new ProviderError(
673
692
  error instanceof Error ? error.message : String(error),
674
- "google",
693
+ provider,
675
694
  void 0,
676
695
  error
677
696
  );
678
697
  }
679
698
 
680
699
  // src/chat-model.ts
681
- function createGoogleGenAIChatModel(client, modelId) {
682
- const provider = "google";
700
+ function createGoogleGenAIChatModel(client, modelId, provider = "google") {
683
701
  async function callGenerateContentApi(request) {
684
702
  try {
685
703
  return await client.models.generateContent(request);
686
704
  } catch (error) {
687
- throw wrapGoogleError(error);
705
+ throw wrapGoogleError(error, provider);
688
706
  }
689
707
  }
690
708
  async function callGenerateContentStreamApi(request) {
691
709
  try {
692
710
  return await client.models.generateContentStream(request);
693
711
  } catch (error) {
694
- throw wrapGoogleError(error);
712
+ throw wrapGoogleError(error, provider);
695
713
  }
696
714
  }
697
715
  async function generateChat(options) {
@@ -899,9 +917,9 @@ function formatZodIssues(issues) {
899
917
  }
900
918
 
901
919
  // src/embedding-model.ts
902
- function createGoogleGenAIEmbeddingModel(client, modelId) {
920
+ function createGoogleGenAIEmbeddingModel(client, modelId, provider = "google") {
903
921
  return {
904
- provider: "google",
922
+ provider,
905
923
  modelId,
906
924
  async embed(options) {
907
925
  try {
@@ -942,7 +960,7 @@ function createGoogleGenAIEmbeddingModel(client, modelId) {
942
960
  usage
943
961
  };
944
962
  } catch (error) {
945
- throw wrapGoogleError(error);
963
+ throw wrapGoogleError(error, provider);
946
964
  }
947
965
  }
948
966
  };
@@ -957,46 +975,107 @@ function mapGoogleEmbedProviderOptionsToConfig(options) {
957
975
  }
958
976
 
959
977
  // src/image-model.ts
960
- function createGoogleGenAIImageModel(client, modelId) {
978
+ function createGoogleGenAIImageModel(client, modelId, provider = "google") {
961
979
  return {
962
- provider: "google",
980
+ provider,
963
981
  modelId,
964
982
  async generate(options) {
965
983
  try {
966
- const baseRequest = {
967
- model: modelId,
968
- prompt: options.prompt,
969
- config: {
970
- ...options.n !== void 0 ? { numberOfImages: options.n } : {},
971
- ...mapSizeToImageConfig(options.size)
972
- }
973
- };
974
984
  const googleOptions = parseGoogleImageProviderOptions(
975
985
  options.providerOptions
976
986
  );
977
- const providerConfig = mapGoogleImageProviderOptionsToConfig(googleOptions);
978
- const request = Object.keys(providerConfig).length > 0 ? {
979
- ...baseRequest,
980
- config: {
981
- ...baseRequest.config,
982
- ...providerConfig
983
- }
984
- } : baseRequest;
985
- const response = await client.models.generateImages(request);
986
- return {
987
- images: (response.generatedImages ?? []).map((image) => ({
988
- base64: image.image?.imageBytes ?? void 0,
989
- url: image.image?.gcsUri ?? void 0,
990
- revisedPrompt: image.enhancedPrompt ?? void 0
991
- }))
992
- };
987
+ return isGeminiImageModel(modelId) ? await generateGeminiImages(
988
+ client,
989
+ modelId,
990
+ options,
991
+ googleOptions
992
+ ) : await generateImagenImages(
993
+ client,
994
+ modelId,
995
+ options,
996
+ googleOptions
997
+ );
993
998
  } catch (error) {
994
- throw wrapGoogleError(error);
999
+ throw wrapGoogleError(error, provider);
1000
+ }
1001
+ }
1002
+ };
1003
+ }
1004
+ function isGeminiImageModel(modelId) {
1005
+ return modelId.startsWith("gemini-");
1006
+ }
1007
+ async function generateGeminiImages(client, modelId, options, googleOptions) {
1008
+ if (options.n !== void 0 && options.n > 1) {
1009
+ throw new Error(
1010
+ "Gemini image generation does not support n greater than 1."
1011
+ );
1012
+ }
1013
+ const sizeConfig = mapSizeToImageConfig(options.size);
1014
+ const aspectRatio = googleOptions?.aspectRatio ?? sizeConfig["aspectRatio"];
1015
+ const imageSize = supportsGeminiImageSize(modelId) ? googleOptions?.imageSize ?? sizeConfig["imageSize"] : void 0;
1016
+ const imageConfig = {
1017
+ ...aspectRatio ? { aspectRatio } : {},
1018
+ ...imageSize ? { imageSize } : {}
1019
+ };
1020
+ const request = {
1021
+ model: modelId,
1022
+ contents: [
1023
+ {
1024
+ role: "user",
1025
+ parts: [{ text: options.prompt }]
1026
+ }
1027
+ ],
1028
+ config: {
1029
+ responseModalities: ["IMAGE"],
1030
+ ...Object.keys(imageConfig).length > 0 ? { imageConfig } : {},
1031
+ ...googleOptions?.seed !== void 0 ? { seed: googleOptions.seed } : {}
1032
+ }
1033
+ };
1034
+ const response = await client.models.generateContent(request);
1035
+ return mapGeminiImageResponse(response);
1036
+ }
1037
+ function supportsGeminiImageSize(modelId) {
1038
+ return !modelId.startsWith("gemini-2.5-flash-image");
1039
+ }
1040
+ function mapGeminiImageResponse(response) {
1041
+ const parts = response.candidates?.[0]?.content?.parts ?? [];
1042
+ return {
1043
+ images: parts.flatMap((part) => {
1044
+ const inlineData = part.inlineData;
1045
+ if (!inlineData?.data || !inlineData.mimeType?.startsWith("image/")) {
1046
+ return [];
995
1047
  }
1048
+ return [{ base64: inlineData.data }];
1049
+ })
1050
+ };
1051
+ }
1052
+ async function generateImagenImages(client, modelId, options, googleOptions) {
1053
+ const baseRequest = {
1054
+ model: modelId,
1055
+ prompt: options.prompt,
1056
+ config: {
1057
+ ...options.n !== void 0 ? { numberOfImages: options.n } : {},
1058
+ ...mapSizeToImageConfig(options.size)
996
1059
  }
997
1060
  };
1061
+ const providerConfig = mapImagenImageProviderOptionsToConfig(googleOptions);
1062
+ const request = Object.keys(providerConfig).length > 0 ? {
1063
+ ...baseRequest,
1064
+ config: {
1065
+ ...baseRequest.config,
1066
+ ...providerConfig
1067
+ }
1068
+ } : baseRequest;
1069
+ const response = await client.models.generateImages(request);
1070
+ return {
1071
+ images: (response.generatedImages ?? []).map((image) => ({
1072
+ base64: image.image?.imageBytes ?? void 0,
1073
+ url: image.image?.gcsUri ?? void 0,
1074
+ revisedPrompt: image.enhancedPrompt ?? void 0
1075
+ }))
1076
+ };
998
1077
  }
999
- function mapGoogleImageProviderOptionsToConfig(options) {
1078
+ function mapImagenImageProviderOptionsToConfig(options) {
1000
1079
  return {
1001
1080
  ...options?.outputGcsUri !== void 0 ? { outputGcsUri: options.outputGcsUri } : {},
1002
1081
  ...options?.negativePrompt !== void 0 ? { negativePrompt: options.negativePrompt } : {},
@@ -1052,7 +1131,8 @@ function greatestCommonDivisor(a, b) {
1052
1131
  }
1053
1132
 
1054
1133
  // src/provider.ts
1055
- function createGoogleGenAI(options = {}) {
1134
+ var DEFAULT_PROVIDER_ID = "google";
1135
+ function createGoogleGenAIProvider(options = {}, factoryOptions = {}) {
1056
1136
  const client = options.client ?? new GoogleGenAI({
1057
1137
  apiKey: options.apiKey,
1058
1138
  ...options.apiVersion ? { apiVersion: options.apiVersion } : {},
@@ -1062,14 +1142,19 @@ function createGoogleGenAI(options = {}) {
1062
1142
  }
1063
1143
  } : {}
1064
1144
  });
1145
+ const providerId = factoryOptions.providerId ?? DEFAULT_PROVIDER_ID;
1065
1146
  return {
1066
- chatModel: (modelId) => createGoogleGenAIChatModel(client, modelId),
1067
- embeddingModel: (modelId) => createGoogleGenAIEmbeddingModel(client, modelId),
1068
- imageModel: (modelId) => createGoogleGenAIImageModel(client, modelId)
1147
+ chatModel: (modelId) => createGoogleGenAIChatModel(client, modelId, providerId),
1148
+ embeddingModel: (modelId) => createGoogleGenAIEmbeddingModel(client, modelId, providerId),
1149
+ imageModel: (modelId) => createGoogleGenAIImageModel(client, modelId, providerId)
1069
1150
  };
1070
1151
  }
1152
+ function createGoogleGenAI(options = {}) {
1153
+ return createGoogleGenAIProvider(options);
1154
+ }
1071
1155
  export {
1072
1156
  createGoogleGenAI,
1157
+ createGoogleGenAIProvider,
1073
1158
  getGoogleModelCapabilities,
1074
1159
  googleEmbedProviderOptionsSchema,
1075
1160
  googleGenerateProviderOptionsSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@core-ai/google-genai",
3
- "version": "0.13.1",
3
+ "version": "0.15.0",
4
4
  "description": "Google GenAI provider package for @core-ai/core-ai",
5
5
  "license": "MIT",
6
6
  "author": "Omnifact (https://omnifact.ai)",
@@ -45,7 +45,7 @@
45
45
  "test:watch": "vitest"
46
46
  },
47
47
  "dependencies": {
48
- "@core-ai/core-ai": "^0.13.1",
48
+ "@core-ai/core-ai": "^0.15.0",
49
49
  "@google/genai": "^1.42.0"
50
50
  },
51
51
  "peerDependencies": {