@anvia/gemini 0.4.1 → 1.0.0-rc.2

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/dist/index.js CHANGED
@@ -10,15 +10,13 @@ __export(gemini_exports, {
10
10
  GEMINI_2_5_FLASH_IMAGE: () => GEMINI_2_5_FLASH_IMAGE,
11
11
  GEMINI_3_PRO_IMAGE_PREVIEW: () => GEMINI_3_PRO_IMAGE_PREVIEW,
12
12
  GeminiClient: () => GeminiClient,
13
- GeminiCompletionModel: () => GeminiCompletionModel,
14
- GeminiEmbeddingModel: () => GeminiEmbeddingModel,
15
- GeminiImageGenerationModel: () => GeminiImageGenerationModel,
16
- GeminiImagenGenerationModel: () => GeminiImagenGenerationModel,
17
- GeminiTranscriptionModel: () => GeminiTranscriptionModel,
18
13
  IMAGEN_4_GENERATE: () => IMAGEN_4_GENERATE
19
14
  });
20
15
 
21
16
  // src/gemini/client.ts
17
+ import {
18
+ resolveModelContextLimits
19
+ } from "@anvia/core/completion";
22
20
  import {
23
21
  ModelListingError
24
22
  } from "@anvia/core/model-listing";
@@ -26,9 +24,7 @@ import { GoogleGenAI } from "@google/genai";
26
24
 
27
25
  // src/gemini/completion.ts
28
26
  import {
29
- AssistantContent,
30
27
  assertCompletionRequestSupported,
31
- resolveCompletionModelInfo,
32
28
  Usage,
33
29
  withContextUsage
34
30
  } from "@anvia/core/completion";
@@ -48,82 +44,35 @@ function orderedRequestMessages(request) {
48
44
  return messages;
49
45
  }
50
46
 
51
- // src/gemini/models.ts
52
- var CONTEXT_1M_64K = {
53
- contextWindow: 1048576,
54
- maxInputTokens: 1048576,
55
- maxOutputTokens: 65536
56
- };
57
- var GEMINI_COMPLETION_MODEL_CONTEXT_LIMITS = {
58
- "gemini-2.0-flash": {
59
- contextWindow: 1048576,
60
- maxInputTokens: 1048576,
61
- maxOutputTokens: 8192
62
- },
63
- "gemini-2.0-flash-lite": {
64
- contextWindow: 1048576,
65
- maxInputTokens: 1048576,
66
- maxOutputTokens: 8192
67
- },
68
- "gemini-2.5-flash": CONTEXT_1M_64K,
69
- "gemini-2.5-flash-image": {
70
- contextWindow: 32768,
71
- maxInputTokens: 32768,
72
- maxOutputTokens: 32768
73
- },
74
- "gemini-2.5-flash-lite": CONTEXT_1M_64K,
75
- "gemini-2.5-flash-preview-tts": {
76
- contextWindow: 8192,
77
- maxInputTokens: 8192,
78
- maxOutputTokens: 16384
79
- },
80
- "gemini-2.5-pro": CONTEXT_1M_64K,
81
- "gemini-2.5-pro-preview-tts": {
82
- contextWindow: 8192,
83
- maxInputTokens: 8192,
84
- maxOutputTokens: 16384
85
- },
86
- "gemini-3-flash-preview": CONTEXT_1M_64K,
87
- "gemini-3-pro-image-preview": {
88
- contextWindow: 131072,
89
- maxInputTokens: 131072,
90
- maxOutputTokens: 32768
91
- },
92
- "gemini-3-pro-preview": CONTEXT_1M_64K,
93
- "gemini-3.1-flash-image-preview": {
94
- contextWindow: 65536,
95
- maxInputTokens: 65536,
96
- maxOutputTokens: 65536
97
- },
98
- "gemini-3.1-flash-lite": CONTEXT_1M_64K,
99
- "gemini-3.1-flash-lite-preview": CONTEXT_1M_64K,
100
- "gemini-3.1-pro-preview": CONTEXT_1M_64K,
101
- "gemini-3.1-pro-preview-customtools": CONTEXT_1M_64K,
102
- "gemini-3.5-flash": CONTEXT_1M_64K,
103
- "gemini-flash-latest": CONTEXT_1M_64K,
104
- "gemini-flash-lite-latest": CONTEXT_1M_64K,
105
- "gemma-4-26b-a4b-it": {
106
- contextWindow: 262144,
107
- maxInputTokens: 262144,
108
- maxOutputTokens: 32768
109
- },
110
- "gemma-4-31b-it": {
111
- contextWindow: 262144,
112
- maxInputTokens: 262144,
113
- maxOutputTokens: 32768
114
- }
115
- };
47
+ // src/gemini/retry.ts
48
+ function disableGeminiNativeRetries(config) {
49
+ const httpOptions = isPlainObject(config.httpOptions) ? config.httpOptions : {};
50
+ const retryOptions = isPlainObject(httpOptions.retryOptions) ? httpOptions.retryOptions : {};
51
+ return {
52
+ ...config,
53
+ httpOptions: {
54
+ ...httpOptions,
55
+ retryOptions: {
56
+ ...retryOptions,
57
+ attempts: 1
58
+ }
59
+ }
60
+ };
61
+ }
62
+ function isPlainObject(value) {
63
+ return typeof value === "object" && value !== null && !Array.isArray(value);
64
+ }
116
65
 
117
66
  // src/gemini/completion.ts
118
67
  var GeminiCompletionModel = class {
119
- constructor(client, defaultModel = "gemini-2.5-flash", metadataOptions = {}) {
68
+ constructor(client, modelId, contextLimits) {
120
69
  this.client = client;
121
- this.defaultModel = defaultModel;
122
- this.metadataOptions = metadataOptions;
70
+ this.modelId = modelId;
71
+ this.contextLimits = contextLimits;
123
72
  }
124
73
  client;
125
- defaultModel;
126
- metadataOptions;
74
+ modelId;
75
+ contextLimits;
127
76
  provider = "gemini";
128
77
  capabilities = {
129
78
  streaming: true,
@@ -134,62 +83,60 @@ var GeminiCompletionModel = class {
134
83
  outputSchema: true,
135
84
  reasoning: true
136
85
  };
137
- getModelInfo(model = this.defaultModel) {
138
- return resolveCompletionModelInfo(
139
- model,
140
- GEMINI_COMPLETION_MODEL_CONTEXT_LIMITS,
141
- this.metadataOptions.modelOverrides
142
- );
86
+ modelInfo() {
87
+ return this.contextLimits === void 0 ? void 0 : { modelId: this.modelId, context: this.contextLimits };
143
88
  }
144
89
  traceRequest(request, options = {}) {
145
- const params = toGeminiGenerateContentParams(this.defaultModel, request);
90
+ const params = toGeminiGenerateContentParams(this.modelId, request);
146
91
  return providerRequestSummary(params, request, options);
147
92
  }
148
- async completion(request) {
93
+ async completion(request, options) {
149
94
  assertCompletionRequestSupported(this, request);
150
- const params = toGeminiGenerateContentParams(this.defaultModel, request);
95
+ const params = toGeminiGenerateContentParams(this.modelId, request);
96
+ applyAbortSignal(params, options);
151
97
  const response = await this.client.models.generateContent(params);
152
- return withContextUsage(
153
- fromGeminiGenerateContentResponse(response),
154
- this.getModelInfo(request.model ?? this.defaultModel)
155
- );
98
+ return withContextUsage(fromGeminiGenerateContentResponse(response), this.modelInfo());
156
99
  }
157
- async *streamCompletion(request) {
100
+ async *streamCompletion(request, options) {
158
101
  assertCompletionRequestSupported(this, request, { streaming: true });
159
- const params = toGeminiGenerateContentParams(this.defaultModel, request);
102
+ const params = toGeminiGenerateContentParams(this.modelId, request);
103
+ applyAbortSignal(params, options);
160
104
  const stream = await this.client.models.generateContentStream(params);
161
105
  for await (const chunk of stream) {
162
106
  for (const event of fromGeminiGenerateContentStreamChunk(chunk)) {
163
107
  yield event.type === "final" ? {
164
108
  ...event,
165
- response: withContextUsage(
166
- event.response,
167
- this.getModelInfo(request.model ?? this.defaultModel)
168
- )
109
+ response: withContextUsage(event.response, this.modelInfo())
169
110
  } : event;
170
111
  }
171
112
  }
172
113
  }
173
114
  };
174
- function toGeminiGenerateContentParams(defaultModel, request) {
115
+ function toGeminiGenerateContentParams(modelId, request) {
175
116
  const messages = requestMessages(request);
176
- const config = geminiConfig(request, messages);
117
+ const providerOptions = isPlainObject2(request.providerOptions) ? request.providerOptions : {};
118
+ const { config: providerConfigValue, ...providerTopLevel } = providerOptions;
119
+ const providerConfig = isPlainObject2(providerConfigValue) ? { ...providerConfigValue } : {};
120
+ delete providerConfig.tools;
121
+ const config = disableGeminiNativeRetries({
122
+ ...providerConfig,
123
+ ...geminiConfig(request, messages)
124
+ });
177
125
  const params = {
178
- model: request.model ?? defaultModel,
126
+ ...providerTopLevel,
127
+ model: modelId,
179
128
  contents: messagesToGeminiContents(messages),
180
129
  config
181
130
  };
182
- if (request.additionalParams !== void 0 && isPlainObject(request.additionalParams)) {
183
- const { config: additionalConfig, ...additionalTopLevel } = request.additionalParams;
184
- Object.assign(params, additionalTopLevel);
185
- if (isPlainObject(additionalConfig)) {
186
- params.config = { ...config, ...additionalConfig };
187
- }
188
- }
189
131
  return params;
190
132
  }
133
+ function applyAbortSignal(params, options) {
134
+ if (options?.abortSignal === void 0) return;
135
+ const config = isPlainObject2(params.config) ? params.config : {};
136
+ params.config = { ...config, abortSignal: options.abortSignal };
137
+ }
191
138
  function providerRequestSummary(params, request, options) {
192
- const config = isPlainObject(params.config) ? params.config : {};
139
+ const config = isPlainObject2(params.config) ? params.config : {};
193
140
  return compactJsonObject({
194
141
  provider: "gemini",
195
142
  api: options.stream === true ? "models.generateContentStream" : "models.generateContent",
@@ -205,7 +152,7 @@ function providerRequestSummary(params, request, options) {
205
152
  temperature: request.temperature,
206
153
  maxTokens: request.maxTokens,
207
154
  toolChoice: toolChoiceSummary(request.toolChoice),
208
- additionalParamKeys: isPlainObject(request.additionalParams) ? Object.keys(request.additionalParams).sort() : void 0
155
+ providerOptionKeys: isPlainObject2(request.providerOptions) ? Object.keys(request.providerOptions).sort() : void 0
209
156
  });
210
157
  }
211
158
  function toolChoiceSummary(toolChoice) {
@@ -269,11 +216,11 @@ function messagesToGeminiContents(messages) {
269
216
  }
270
217
  if (message.role === "assistant") {
271
218
  const content2 = assistantMessageToGeminiContent(message);
272
- for (const item of message.content) {
273
- if (item.type === "tool_call") {
274
- toolNamesById.set(item.id, item.function.name);
219
+ for (const item of typeof message.content === "string" ? [] : message.content) {
220
+ if (item.type === "tool-call") {
221
+ toolNamesById.set(item.toolCallId, item.toolName);
275
222
  if (item.callId !== void 0) {
276
- toolNamesById.set(item.callId, item.function.name);
223
+ toolNamesById.set(item.callId, item.toolName);
277
224
  }
278
225
  }
279
226
  }
@@ -292,7 +239,7 @@ function messagesToGeminiContents(messages) {
292
239
  function userMessageToGeminiContent(message) {
293
240
  return {
294
241
  role: "user",
295
- parts: message.content.map(userContentToGeminiPart)
242
+ parts: typeof message.content === "string" ? [{ text: message.content }] : message.content.map(userContentToGeminiPart)
296
243
  };
297
244
  }
298
245
  function toolMessageToGeminiContent(message, toolNamesById) {
@@ -304,7 +251,7 @@ function toolMessageToGeminiContent(message, toolNamesById) {
304
251
  function assistantMessageToGeminiContent(message) {
305
252
  return {
306
253
  role: "model",
307
- parts: message.content.flatMap((content) => {
254
+ parts: typeof message.content === "string" ? [{ text: message.content }] : message.content.flatMap((content) => {
308
255
  if (content.type === "text") {
309
256
  const part = { text: content.text };
310
257
  if (content.signature !== void 0) {
@@ -312,10 +259,10 @@ function assistantMessageToGeminiContent(message) {
312
259
  }
313
260
  return [part];
314
261
  }
315
- if (content.type === "tool_call") {
262
+ if (content.type === "tool-call") {
316
263
  const functionCall = {
317
- name: content.function.name,
318
- args: content.function.arguments ?? {}
264
+ name: content.toolName,
265
+ args: content.input
319
266
  };
320
267
  if (content.callId !== void 0) {
321
268
  functionCall.id = content.callId;
@@ -326,8 +273,8 @@ function assistantMessageToGeminiContent(message) {
326
273
  }
327
274
  return [part];
328
275
  }
329
- if (content.type === "reasoning" && content.content !== void 0) {
330
- return content.content.flatMap((reasoning) => {
276
+ if (content.type === "reasoning" && content.details !== void 0) {
277
+ return content.details.flatMap((reasoning) => {
331
278
  if (reasoning.type !== "text" && reasoning.type !== "summary") {
332
279
  return [];
333
280
  }
@@ -338,8 +285,10 @@ function assistantMessageToGeminiContent(message) {
338
285
  return [part];
339
286
  });
340
287
  }
341
- if (content.type === "image") {
342
- throw new Error("Gemini does not support image content in assistant history yet");
288
+ if (content.type === "image" || content.type === "file") {
289
+ throw new Error(
290
+ "Gemini does not support image or file content in assistant history yet"
291
+ );
343
292
  }
344
293
  return [];
345
294
  })
@@ -355,18 +304,18 @@ function userContentToGeminiPart(content) {
355
304
  return documentContentToGeminiPart(content);
356
305
  }
357
306
  function imageContentToGeminiPart(content) {
358
- if (content.source.type === "base64") {
307
+ if (content.image.type === "data") {
359
308
  return {
360
309
  inlineData: {
361
- mimeType: content.source.mediaType,
362
- data: content.source.data
310
+ mimeType: content.mediaType ?? "image/png",
311
+ data: content.image.data
363
312
  }
364
313
  };
365
314
  }
366
315
  return {
367
316
  fileData: {
368
- fileUri: content.source.url,
369
- mimeType: mimeTypeFromImageUrl(content.source.url)
317
+ fileUri: content.image.url,
318
+ mimeType: content.mediaType ?? mimeTypeFromImageUrl(content.image.url)
370
319
  }
371
320
  };
372
321
  }
@@ -388,29 +337,29 @@ function safeUrlPathname(url) {
388
337
  }
389
338
  }
390
339
  function documentContentToGeminiPart(content) {
391
- if (content.source.type === "text") {
392
- return { text: content.source.text };
340
+ if (content.data.type === "text") {
341
+ return { text: content.data.text };
393
342
  }
394
- if (content.source.type === "base64") {
343
+ if (content.data.type === "data") {
395
344
  return {
396
345
  inlineData: {
397
- mimeType: content.source.mediaType,
398
- data: content.source.data
346
+ mimeType: content.mediaType,
347
+ data: content.data.data
399
348
  }
400
349
  };
401
350
  }
402
351
  return {
403
352
  fileData: {
404
- fileUri: content.source.url,
405
- mimeType: content.source.mediaType
353
+ fileUri: content.data.url,
354
+ mimeType: content.mediaType
406
355
  }
407
356
  };
408
357
  }
409
358
  function toolContentToGeminiPart(content, toolNamesById) {
410
- const id = content.callId ?? content.id;
359
+ const id = content.callId ?? content.toolCallId;
411
360
  const functionResponse = {
412
- name: content.toolName ?? toolNamesById.get(id) ?? content.id,
413
- response: toolResultResponse(content.content)
361
+ name: content.toolName || toolNamesById.get(id) || content.toolCallId,
362
+ response: toolResultResponse(content)
414
363
  };
415
364
  if (content.callId !== void 0) {
416
365
  functionResponse.id = content.callId;
@@ -418,10 +367,21 @@ function toolContentToGeminiPart(content, toolNamesById) {
418
367
  return { functionResponse };
419
368
  }
420
369
  function toolResultResponse(content) {
370
+ const output = content.output;
371
+ if (output.type === "json") {
372
+ return { result: output.value };
373
+ }
374
+ if (output.type === "text") {
375
+ return { content: output.value };
376
+ }
377
+ if (output.type === "error-json" || output.type === "error-text") {
378
+ return { error: output.value };
379
+ }
380
+ if (output.type === "execution-denied") {
381
+ return { error: output.reason ?? "Tool execution was denied." };
382
+ }
421
383
  return {
422
- content: content.map(
423
- (item) => item.type === "text" ? item.text : `[image:${item.mediaType ?? "image/png"}]`
424
- ).join("\n")
384
+ content: output.value.map((item) => item.type === "text" ? item.text : `[file:${item.mediaType}]`).join("\n")
425
385
  };
426
386
  }
427
387
  function toolDefinitionToGemini(tool) {
@@ -463,7 +423,7 @@ function fromGeminiGenerateContentResponse(response) {
463
423
  return result;
464
424
  }
465
425
  function fromGeminiGenerateContentStreamChunk(chunk) {
466
- if (!isPlainObject(chunk)) {
426
+ if (!isPlainObject2(chunk)) {
467
427
  return [];
468
428
  }
469
429
  const events = [];
@@ -500,7 +460,7 @@ function fromGeminiGenerateContentStreamChunk(chunk) {
500
460
  if (id !== void 0) {
501
461
  events.push({ type: "message_id", id });
502
462
  }
503
- if (isPlainObject(chunk.usageMetadata)) {
463
+ if (isPlainObject2(chunk.usageMetadata)) {
504
464
  events.push({ type: "final", response: fromGeminiGenerateContentResponse(chunk) });
505
465
  }
506
466
  return events;
@@ -509,35 +469,38 @@ function assistantContentFromGeminiResponse(response) {
509
469
  const parts = candidateParts(response);
510
470
  if (parts.length === 0) {
511
471
  const text = textFromGeminiResponse(response);
512
- return text.length > 0 ? [AssistantContent.text(text)] : [];
472
+ return text.length > 0 ? [{ type: "text", text }] : [];
513
473
  }
514
474
  const choice = [];
515
475
  for (const part of parts) {
516
476
  if (typeof part.text === "string" && part.text.length > 0) {
517
477
  if (part.thought === true) {
518
- choice.push(AssistantContent.reasoningSummary(part.text));
478
+ choice.push({
479
+ type: "reasoning",
480
+ text: part.text,
481
+ details: [{ type: "summary", text: part.text }]
482
+ });
519
483
  } else {
520
- const text = AssistantContent.text(part.text);
521
484
  const signature = thoughtSignatureFrom(part);
522
- if (signature !== void 0) {
523
- text.signature = signature;
524
- }
525
- choice.push(text);
485
+ choice.push({
486
+ type: "text",
487
+ text: part.text,
488
+ ...signature === void 0 ? {} : { signature }
489
+ });
526
490
  }
527
491
  }
528
- if (isPlainObject(part.functionCall)) {
492
+ if (isPlainObject2(part.functionCall)) {
529
493
  const call = functionCallFromGeminiPart(part.functionCall, part);
530
494
  if (call !== void 0) {
531
- const toolCall = AssistantContent.toolCall(
532
- call.id ?? crypto.randomUUID(),
533
- call.name,
534
- call.args,
535
- call.id
536
- );
537
- if (call.signature !== void 0) {
538
- toolCall.signature = call.signature;
539
- }
540
- choice.push(toolCall);
495
+ const toolCallId = call.id ?? crypto.randomUUID();
496
+ choice.push({
497
+ type: "tool-call",
498
+ toolCallId,
499
+ ...call.id === void 0 ? {} : { callId: call.id },
500
+ toolName: call.name,
501
+ input: call.args,
502
+ ...call.signature === void 0 ? {} : { signature: call.signature }
503
+ });
541
504
  }
542
505
  }
543
506
  }
@@ -552,14 +515,14 @@ function textFromGeminiResponse(response) {
552
515
  function functionCallsFromGeminiResponse(response) {
553
516
  const directCalls = Array.isArray(response.functionCalls) ? response.functionCalls : Array.isArray(response.function_calls) ? response.function_calls : [];
554
517
  const partCalls = candidateParts(response).flatMap((part) => {
555
- if (!isPlainObject(part.functionCall)) {
518
+ if (!isPlainObject2(part.functionCall)) {
556
519
  return [];
557
520
  }
558
521
  const call = functionCallFromGeminiPart(part.functionCall, part);
559
522
  return call === void 0 ? [] : [call];
560
523
  });
561
524
  const normalizedDirectCalls = directCalls.flatMap((call) => {
562
- if (!isPlainObject(call) || typeof call.name !== "string") {
525
+ if (!isPlainObject2(call) || typeof call.name !== "string") {
563
526
  return [];
564
527
  }
565
528
  const normalized = {
@@ -599,14 +562,14 @@ function functionCallFromGeminiPart(call, part) {
599
562
  function candidateParts(response) {
600
563
  const candidates = Array.isArray(response.candidates) ? response.candidates : [];
601
564
  return candidates.flatMap((candidate) => {
602
- if (!isPlainObject(candidate) || !isPlainObject(candidate.content)) {
565
+ if (!isPlainObject2(candidate) || !isPlainObject2(candidate.content)) {
603
566
  return [];
604
567
  }
605
- return Array.isArray(candidate.content.parts) ? candidate.content.parts.filter(isPlainObject) : [];
568
+ return Array.isArray(candidate.content.parts) ? candidate.content.parts.filter(isPlainObject2) : [];
606
569
  });
607
570
  }
608
571
  function usageFromGemini(usage) {
609
- const raw = isPlainObject(usage) ? usage : {};
572
+ const raw = isPlainObject2(usage) ? usage : {};
610
573
  const promptInputTokens = numberFrom(raw.promptTokenCount);
611
574
  const toolInputTokens = numberFrom(raw.toolUsePromptTokenCount);
612
575
  const inputTokens = promptInputTokens + toolInputTokens;
@@ -632,12 +595,12 @@ function usageFromGemini(usage) {
632
595
  };
633
596
  }
634
597
  function toJsonValue(value) {
635
- if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || Array.isArray(value) || isPlainObject(value)) {
598
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || Array.isArray(value) || isPlainObject2(value)) {
636
599
  return value;
637
600
  }
638
601
  return String(value);
639
602
  }
640
- function isPlainObject(value) {
603
+ function isPlainObject2(value) {
641
604
  return typeof value === "object" && value !== null && !Array.isArray(value);
642
605
  }
643
606
  function numberFrom(value) {
@@ -661,36 +624,40 @@ function toolCallDelta(id, values) {
661
624
 
662
625
  // src/gemini/embedding.ts
663
626
  var GeminiEmbeddingModel = class {
664
- constructor(client, model, options = {}) {
627
+ constructor(client, options) {
665
628
  this.client = client;
666
- this.model = model;
629
+ this.modelId = options.modelId;
667
630
  this.dimensions = options.dimensions;
668
631
  this.maxBatchSize = options.maxBatchSize ?? 100;
669
632
  this.taskType = options.taskType;
670
633
  this.title = options.title;
671
634
  }
672
635
  client;
673
- model;
636
+ provider = "gemini";
637
+ modelId;
674
638
  dimensions;
675
639
  maxBatchSize;
676
640
  taskType;
677
641
  title;
678
- async embedTexts(texts) {
642
+ async embedTexts(texts, options) {
679
643
  const embeddings = [];
680
644
  for (let index = 0; index < texts.length; index += this.maxBatchSize) {
681
645
  const batch = texts.slice(index, index + this.maxBatchSize);
682
- embeddings.push(...await this.embedBatch(batch));
646
+ embeddings.push(...await this.embedBatch(batch, options));
683
647
  }
684
648
  return embeddings;
685
649
  }
686
- async embedBatch(texts) {
650
+ async embedBatch(texts, options) {
687
651
  if (texts.length === 0) {
688
652
  return [];
689
653
  }
690
654
  const response = await this.client.models.embedContent({
691
- model: this.model,
655
+ model: this.modelId,
692
656
  contents: texts,
693
- config: this.embeddingConfig()
657
+ config: disableGeminiNativeRetries({
658
+ ...this.embeddingConfig(),
659
+ ...options?.abortSignal === void 0 ? {} : { abortSignal: options.abortSignal }
660
+ })
694
661
  });
695
662
  const rawEmbeddings = embeddingsFromResponse(response);
696
663
  if (rawEmbeddings.length !== texts.length) {
@@ -740,54 +707,58 @@ var GEMINI_2_5_FLASH_IMAGE = "gemini-2.5-flash-image";
740
707
  var GEMINI_3_PRO_IMAGE_PREVIEW = "gemini-3-pro-image-preview";
741
708
  var IMAGEN_4_GENERATE = "imagen-4.0-generate-001";
742
709
  var GeminiImageGenerationModel = class {
743
- constructor(client, defaultModel = GEMINI_2_5_FLASH_IMAGE) {
710
+ constructor(client, modelId) {
744
711
  this.client = client;
745
- this.defaultModel = defaultModel;
712
+ this.modelId = modelId;
746
713
  }
747
714
  client;
748
- defaultModel;
715
+ modelId;
749
716
  provider = "gemini";
750
- async imageGeneration(request) {
717
+ async imageGeneration(request, options) {
718
+ const providerOptions = isPlainObject3(request.providerOptions) ? request.providerOptions : {};
719
+ const { config: providerConfigValue, ...providerTopLevel } = providerOptions;
720
+ const providerConfig = isPlainObject3(providerConfigValue) ? providerConfigValue : {};
721
+ const providerImageConfig = isPlainObject3(providerConfig.imageConfig) ? providerConfig.imageConfig : {};
751
722
  const params = {
752
- model: this.defaultModel,
723
+ ...providerTopLevel,
724
+ model: this.modelId,
753
725
  contents: request.prompt,
754
- config: {
726
+ config: disableGeminiNativeRetries({
727
+ ...providerConfig,
755
728
  responseModalities: ["TEXT", "IMAGE"],
756
- imageConfig: { aspectRatio: aspectRatio(request.width, request.height) }
757
- }
729
+ imageConfig: {
730
+ ...providerImageConfig,
731
+ aspectRatio: aspectRatio(request.width, request.height)
732
+ },
733
+ ...options?.abortSignal === void 0 ? {} : { abortSignal: options.abortSignal }
734
+ })
758
735
  };
759
- if (isPlainObject2(request.additionalParams)) {
760
- const { config, ...topLevel } = request.additionalParams;
761
- Object.assign(params, topLevel);
762
- if (isPlainObject2(config)) {
763
- params.config = { ...params.config, ...config };
764
- }
765
- }
766
736
  const response = await this.client.models.generateContent(params);
767
737
  return nativeImageResponseFromGemini(response);
768
738
  }
769
739
  };
770
740
  var GeminiImagenGenerationModel = class {
771
- constructor(client, defaultModel = IMAGEN_4_GENERATE) {
741
+ constructor(client, modelId) {
772
742
  this.client = client;
773
- this.defaultModel = defaultModel;
743
+ this.modelId = modelId;
774
744
  }
775
745
  client;
776
- defaultModel;
746
+ modelId;
777
747
  provider = "gemini";
778
- async imageGeneration(request) {
748
+ async imageGeneration(request, options) {
749
+ const providerOptions = isPlainObject3(request.providerOptions) ? request.providerOptions : {};
750
+ const { config: providerConfigValue, ...providerTopLevel } = providerOptions;
751
+ const providerConfig = isPlainObject3(providerConfigValue) ? providerConfigValue : {};
779
752
  const params = {
780
- model: this.defaultModel,
753
+ ...providerTopLevel,
754
+ model: this.modelId,
781
755
  prompt: request.prompt,
782
- config: { aspectRatio: aspectRatio(request.width, request.height) }
756
+ config: disableGeminiNativeRetries({
757
+ ...providerConfig,
758
+ aspectRatio: aspectRatio(request.width, request.height),
759
+ ...options?.abortSignal === void 0 ? {} : { abortSignal: options.abortSignal }
760
+ })
783
761
  };
784
- if (isPlainObject2(request.additionalParams)) {
785
- const { config, ...topLevel } = request.additionalParams;
786
- Object.assign(params, topLevel);
787
- if (isPlainObject2(config)) {
788
- params.config = { ...params.config, ...config };
789
- }
790
- }
791
762
  const response = await this.client.models.generateImages(params);
792
763
  return imagenResponseFromGemini(response);
793
764
  }
@@ -796,12 +767,12 @@ function nativeImageResponseFromGemini(response) {
796
767
  const raw = response;
797
768
  const candidates = Array.isArray(raw.candidates) ? raw.candidates : [];
798
769
  const images = candidates.flatMap((candidate) => {
799
- if (!isPlainObject2(candidate) || !isPlainObject2(candidate.content)) {
770
+ if (!isPlainObject3(candidate) || !isPlainObject3(candidate.content)) {
800
771
  return [];
801
772
  }
802
773
  const parts = Array.isArray(candidate.content.parts) ? candidate.content.parts : [];
803
774
  return parts.flatMap((part) => {
804
- if (!isPlainObject2(part) || !isPlainObject2(part.inlineData)) {
775
+ if (!isPlainObject3(part) || !isPlainObject3(part.inlineData)) {
805
776
  return [];
806
777
  }
807
778
  const data = part.inlineData.data;
@@ -816,14 +787,11 @@ function nativeImageResponseFromGemini(response) {
816
787
  ];
817
788
  });
818
789
  });
819
- const image = images[0]?.data;
820
- if (image === void 0) {
790
+ if (images.length === 0) {
821
791
  throw new Error("Gemini image generation response contained no inline image data.");
822
792
  }
823
793
  return {
824
- image,
825
794
  images,
826
- mediaType: images[0]?.mediaType,
827
795
  rawResponse: response
828
796
  };
829
797
  }
@@ -831,7 +799,7 @@ function imagenResponseFromGemini(response) {
831
799
  const raw = response;
832
800
  const images = (Array.isArray(raw.generatedImages) ? raw.generatedImages : []).flatMap(
833
801
  (item) => {
834
- if (!isPlainObject2(item) || !isPlainObject2(item.image)) {
802
+ if (!isPlainObject3(item) || !isPlainObject3(item.image)) {
835
803
  return [];
836
804
  }
837
805
  const imageBytes = item.image.imageBytes;
@@ -846,14 +814,11 @@ function imagenResponseFromGemini(response) {
846
814
  ];
847
815
  }
848
816
  );
849
- const image = images[0]?.data;
850
- if (image === void 0) {
817
+ if (images.length === 0) {
851
818
  throw new Error("Gemini image generation response contained no base64 images.");
852
819
  }
853
820
  return {
854
- image,
855
821
  images,
856
- mediaType: images[0]?.mediaType,
857
822
  rawResponse: response
858
823
  };
859
824
  }
@@ -882,50 +847,114 @@ function decodeBase64Image(value) {
882
847
  }
883
848
  return new Uint8Array(bytes);
884
849
  }
885
- function isPlainObject2(value) {
850
+ function isPlainObject3(value) {
886
851
  return typeof value === "object" && value !== null && !Array.isArray(value);
887
852
  }
888
853
 
854
+ // src/gemini/models.ts
855
+ var CONTEXT_1M_64K = {
856
+ contextWindow: 1048576,
857
+ maxInputTokens: 1048576,
858
+ maxOutputTokens: 65536
859
+ };
860
+ var GEMINI_COMPLETION_MODEL_CONTEXT_LIMITS = {
861
+ "gemini-2.0-flash": {
862
+ contextWindow: 1048576,
863
+ maxInputTokens: 1048576,
864
+ maxOutputTokens: 8192
865
+ },
866
+ "gemini-2.0-flash-lite": {
867
+ contextWindow: 1048576,
868
+ maxInputTokens: 1048576,
869
+ maxOutputTokens: 8192
870
+ },
871
+ "gemini-2.5-flash": CONTEXT_1M_64K,
872
+ "gemini-2.5-flash-image": {
873
+ contextWindow: 32768,
874
+ maxInputTokens: 32768,
875
+ maxOutputTokens: 32768
876
+ },
877
+ "gemini-2.5-flash-lite": CONTEXT_1M_64K,
878
+ "gemini-2.5-flash-preview-tts": {
879
+ contextWindow: 8192,
880
+ maxInputTokens: 8192,
881
+ maxOutputTokens: 16384
882
+ },
883
+ "gemini-2.5-pro": CONTEXT_1M_64K,
884
+ "gemini-2.5-pro-preview-tts": {
885
+ contextWindow: 8192,
886
+ maxInputTokens: 8192,
887
+ maxOutputTokens: 16384
888
+ },
889
+ "gemini-3-flash-preview": CONTEXT_1M_64K,
890
+ "gemini-3-pro-image-preview": {
891
+ contextWindow: 131072,
892
+ maxInputTokens: 131072,
893
+ maxOutputTokens: 32768
894
+ },
895
+ "gemini-3-pro-preview": CONTEXT_1M_64K,
896
+ "gemini-3.1-flash-image-preview": {
897
+ contextWindow: 65536,
898
+ maxInputTokens: 65536,
899
+ maxOutputTokens: 65536
900
+ },
901
+ "gemini-3.1-flash-lite": CONTEXT_1M_64K,
902
+ "gemini-3.1-flash-lite-preview": CONTEXT_1M_64K,
903
+ "gemini-3.1-pro-preview": CONTEXT_1M_64K,
904
+ "gemini-3.1-pro-preview-customtools": CONTEXT_1M_64K,
905
+ "gemini-3.5-flash": CONTEXT_1M_64K,
906
+ "gemini-flash-latest": CONTEXT_1M_64K,
907
+ "gemini-flash-lite-latest": CONTEXT_1M_64K,
908
+ "gemma-4-26b-a4b-it": {
909
+ contextWindow: 262144,
910
+ maxInputTokens: 262144,
911
+ maxOutputTokens: 32768
912
+ },
913
+ "gemma-4-31b-it": {
914
+ contextWindow: 262144,
915
+ maxInputTokens: 262144,
916
+ maxOutputTokens: 32768
917
+ }
918
+ };
919
+
889
920
  // src/gemini/transcription.ts
890
921
  import { Buffer as Buffer3 } from "buffer";
891
922
  var TRANSCRIPTION_PREAMBLE = "Transcribe the provided audio exactly. Do not add additional information.";
892
923
  var GeminiTranscriptionModel = class {
893
- constructor(client, defaultModel = "gemini-2.5-flash") {
924
+ constructor(client, modelId) {
894
925
  this.client = client;
895
- this.defaultModel = defaultModel;
926
+ this.modelId = modelId;
896
927
  }
897
928
  client;
898
- defaultModel;
929
+ modelId;
899
930
  provider = "gemini";
900
- async transcription(request) {
901
- const config = {};
931
+ async transcription(request, options) {
932
+ const config = isPlainObject4(request.providerOptions) ? { ...request.providerOptions } : {};
902
933
  if (request.temperature !== void 0) {
903
934
  config.temperature = request.temperature;
904
935
  }
905
- if (isPlainObject3(request.additionalParams)) {
906
- Object.assign(config, request.additionalParams);
907
- }
936
+ if (options?.abortSignal !== void 0) config.abortSignal = options.abortSignal;
908
937
  const response = await this.client.models.generateContent({
909
- model: this.defaultModel,
938
+ model: this.modelId,
910
939
  contents: [
911
940
  {
912
941
  role: "user",
913
942
  parts: [
914
943
  {
915
944
  inlineData: {
916
- mimeType: mimeTypeFromFilename(request.filename),
945
+ mimeType: request.mediaType ?? mimeTypeFromFilename(request.filename),
917
946
  data: Buffer3.from(request.data).toString("base64")
918
947
  }
919
948
  }
920
949
  ]
921
950
  }
922
951
  ],
923
- config: {
952
+ config: disableGeminiNativeRetries({
924
953
  ...config,
925
954
  systemInstruction: request.prompt === void 0 ? TRANSCRIPTION_PREAMBLE : `${TRANSCRIPTION_PREAMBLE}
926
955
 
927
956
  ${request.prompt}`
928
- }
957
+ })
929
958
  });
930
959
  return {
931
960
  text: textFromGenerateContentResponse(response),
@@ -940,12 +969,12 @@ function textFromGenerateContentResponse(response) {
940
969
  }
941
970
  const candidates = Array.isArray(raw.candidates) ? raw.candidates : [];
942
971
  for (const candidate of candidates) {
943
- if (!isPlainObject3(candidate) || !isPlainObject3(candidate.content)) {
972
+ if (!isPlainObject4(candidate) || !isPlainObject4(candidate.content)) {
944
973
  continue;
945
974
  }
946
975
  const parts = Array.isArray(candidate.content.parts) ? candidate.content.parts : [];
947
976
  for (const part of parts) {
948
- if (isPlainObject3(part) && typeof part.text === "string") {
977
+ if (isPlainObject4(part) && typeof part.text === "string") {
949
978
  return part.text;
950
979
  }
951
980
  }
@@ -962,34 +991,54 @@ function mimeTypeFromFilename(filename) {
962
991
  if (lower.endsWith(".opus")) return "audio/opus";
963
992
  return "audio/mpeg";
964
993
  }
965
- function isPlainObject3(value) {
994
+ function isPlainObject4(value) {
966
995
  return typeof value === "object" && value !== null && !Array.isArray(value);
967
996
  }
968
997
 
969
998
  // src/gemini/client.ts
970
999
  var GeminiClient = class {
971
- client;
972
- constructor(options = {}) {
973
- this.client = options.client ?? new GoogleGenAI(toGoogleGenAIOptions(options));
974
- }
975
- completionModel(model = "gemini-2.5-flash") {
976
- return new GeminiCompletionModel(this.client, model);
977
- }
978
- embeddingModel(model = "gemini-embedding-001", options = {}) {
979
- return new GeminiEmbeddingModel(this.client, model, options);
1000
+ sdk;
1001
+ constructor(options) {
1002
+ if (options.client !== void 0) {
1003
+ rejectManagedOptionsWithInjectedClient(options, ["apiKey", "vertexAi"]);
1004
+ this.sdk = options.client;
1005
+ return;
1006
+ }
1007
+ this.sdk = new GoogleGenAI(toGoogleGenAIOptions(options));
1008
+ }
1009
+ completionModel(options) {
1010
+ const modelId = requireModelId(options.modelId);
1011
+ return new GeminiCompletionModel(
1012
+ this.sdk,
1013
+ modelId,
1014
+ resolveModelContextLimits(
1015
+ modelId,
1016
+ GEMINI_COMPLETION_MODEL_CONTEXT_LIMITS,
1017
+ options.contextLimits
1018
+ )
1019
+ );
980
1020
  }
981
- imageGenerationModel(model = GEMINI_2_5_FLASH_IMAGE) {
982
- return new GeminiImageGenerationModel(this.client, model);
1021
+ embeddingModel(options) {
1022
+ requireModelId(options.modelId);
1023
+ validateOptionalPositiveSafeInteger(options.dimensions, "dimensions");
1024
+ validateOptionalPositiveSafeInteger(options.maxBatchSize, "maxBatchSize");
1025
+ return new GeminiEmbeddingModel(this.sdk, options);
983
1026
  }
984
- imagenGenerationModel(model = IMAGEN_4_GENERATE) {
985
- return new GeminiImagenGenerationModel(this.client, model);
1027
+ imageGenerationModel(options) {
1028
+ const modelId = requireModelId(options.modelId);
1029
+ return options.api === "generateContent" ? new GeminiImageGenerationModel(this.sdk, modelId) : new GeminiImagenGenerationModel(this.sdk, modelId);
986
1030
  }
987
- transcriptionModel(model = "gemini-2.5-flash") {
988
- return new GeminiTranscriptionModel(this.client, model);
1031
+ transcriptionModel(options) {
1032
+ return new GeminiTranscriptionModel(this.sdk, requireModelId(options.modelId));
989
1033
  }
990
- async listModels() {
1034
+ async listModels(options = {}) {
991
1035
  try {
992
- const response = await this.client.models.list({ config: { pageSize: 1e3 } });
1036
+ const response = await this.sdk.models.list({
1037
+ config: disableGeminiNativeRetries({
1038
+ pageSize: 1e3,
1039
+ ...options.abortSignal === void 0 ? {} : { abortSignal: options.abortSignal }
1040
+ })
1041
+ });
993
1042
  const data = (await collectModelsFromResponse(response)).map(toListedModel).filter(isListedModel);
994
1043
  return { data };
995
1044
  } catch (error) {
@@ -997,13 +1046,22 @@ var GeminiClient = class {
997
1046
  }
998
1047
  }
999
1048
  };
1049
+ function rejectManagedOptionsWithInjectedClient(options, keys) {
1050
+ const conflict = keys.find((key) => key in options);
1051
+ if (conflict !== void 0) {
1052
+ throw new TypeError(`GeminiClient cannot combine client with ${conflict}.`);
1053
+ }
1054
+ }
1000
1055
  function toGoogleGenAIOptions(options) {
1001
- if (options.vertexai === true) {
1056
+ if ("client" in options && options.client !== void 0) {
1057
+ throw new TypeError("Injected Gemini clients do not have managed SDK options.");
1058
+ }
1059
+ if ("vertexAi" in options && options.vertexAi !== void 0) {
1002
1060
  return {
1003
1061
  vertexai: true,
1004
- project: requireOption(options.project, "project", "Vertex Gemini"),
1005
- location: requireOption(options.location, "location", "Vertex Gemini"),
1006
- ...options.googleAuthOptions === void 0 ? {} : { googleAuthOptions: options.googleAuthOptions }
1062
+ project: requireOption(options.vertexAi.projectId, "projectId", "Vertex Gemini"),
1063
+ location: requireOption(options.vertexAi.location, "location", "Vertex Gemini"),
1064
+ ...options.vertexAi.googleAuthOptions === void 0 ? {} : { googleAuthOptions: options.vertexAi.googleAuthOptions }
1007
1065
  };
1008
1066
  }
1009
1067
  return {
@@ -1011,11 +1069,22 @@ function toGoogleGenAIOptions(options) {
1011
1069
  };
1012
1070
  }
1013
1071
  function requireOption(value, name, label) {
1014
- if (value === void 0 || value.length === 0) {
1072
+ if (value === void 0 || value.trim().length === 0) {
1015
1073
  throw new Error(`Missing ${label} ${name}. Pass ${name} when constructing GeminiClient.`);
1016
1074
  }
1017
1075
  return value;
1018
1076
  }
1077
+ function requireModelId(modelId) {
1078
+ if (modelId.trim().length === 0) {
1079
+ throw new TypeError("modelId must be a non-empty string");
1080
+ }
1081
+ return modelId;
1082
+ }
1083
+ function validateOptionalPositiveSafeInteger(value, name) {
1084
+ if (value !== void 0 && (!Number.isSafeInteger(value) || value <= 0)) {
1085
+ throw new TypeError(`${name} must be a positive safe integer`);
1086
+ }
1087
+ }
1019
1088
  async function collectModelsFromResponse(response) {
1020
1089
  if (isAsyncIterable(response)) {
1021
1090
  const models = [];
@@ -1116,11 +1185,6 @@ export {
1116
1185
  GEMINI_2_5_FLASH_IMAGE,
1117
1186
  GEMINI_3_PRO_IMAGE_PREVIEW,
1118
1187
  GeminiClient,
1119
- GeminiCompletionModel,
1120
- GeminiEmbeddingModel,
1121
- GeminiImageGenerationModel,
1122
- GeminiImagenGenerationModel,
1123
- GeminiTranscriptionModel,
1124
1188
  IMAGEN_4_GENERATE,
1125
1189
  gemini_exports as gemini
1126
1190
  };