@anvia/gemini 1.0.0-rc.1 → 1.0.0-rc.3

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,19 +239,26 @@ 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) {
299
246
  return {
300
247
  role: "user",
301
- parts: message.content.map((content) => toolContentToGeminiPart(content, toolNamesById))
248
+ parts: message.content.map((content) => {
249
+ if (content.type !== "tool-result") {
250
+ throw new TypeError(
251
+ "Anvia interaction responses must be resolved by Agent before provider calls."
252
+ );
253
+ }
254
+ return toolContentToGeminiPart(content, toolNamesById);
255
+ })
302
256
  };
303
257
  }
304
258
  function assistantMessageToGeminiContent(message) {
305
259
  return {
306
260
  role: "model",
307
- parts: message.content.flatMap((content) => {
261
+ parts: typeof message.content === "string" ? [{ text: message.content }] : message.content.flatMap((content) => {
308
262
  if (content.type === "text") {
309
263
  const part = { text: content.text };
310
264
  if (content.signature !== void 0) {
@@ -312,10 +266,10 @@ function assistantMessageToGeminiContent(message) {
312
266
  }
313
267
  return [part];
314
268
  }
315
- if (content.type === "tool_call") {
269
+ if (content.type === "tool-call") {
316
270
  const functionCall = {
317
- name: content.function.name,
318
- args: content.function.arguments ?? {}
271
+ name: content.toolName,
272
+ args: content.input
319
273
  };
320
274
  if (content.callId !== void 0) {
321
275
  functionCall.id = content.callId;
@@ -326,8 +280,8 @@ function assistantMessageToGeminiContent(message) {
326
280
  }
327
281
  return [part];
328
282
  }
329
- if (content.type === "reasoning" && content.content !== void 0) {
330
- return content.content.flatMap((reasoning) => {
283
+ if (content.type === "reasoning" && content.details !== void 0) {
284
+ return content.details.flatMap((reasoning) => {
331
285
  if (reasoning.type !== "text" && reasoning.type !== "summary") {
332
286
  return [];
333
287
  }
@@ -338,8 +292,10 @@ function assistantMessageToGeminiContent(message) {
338
292
  return [part];
339
293
  });
340
294
  }
341
- if (content.type === "image") {
342
- throw new Error("Gemini does not support image content in assistant history yet");
295
+ if (content.type === "image" || content.type === "file") {
296
+ throw new Error(
297
+ "Gemini does not support image or file content in assistant history yet"
298
+ );
343
299
  }
344
300
  return [];
345
301
  })
@@ -355,18 +311,18 @@ function userContentToGeminiPart(content) {
355
311
  return documentContentToGeminiPart(content);
356
312
  }
357
313
  function imageContentToGeminiPart(content) {
358
- if (content.source.type === "base64") {
314
+ if (content.image.type === "data") {
359
315
  return {
360
316
  inlineData: {
361
- mimeType: content.source.mediaType,
362
- data: content.source.data
317
+ mimeType: content.mediaType ?? "image/png",
318
+ data: content.image.data
363
319
  }
364
320
  };
365
321
  }
366
322
  return {
367
323
  fileData: {
368
- fileUri: content.source.url,
369
- mimeType: mimeTypeFromImageUrl(content.source.url)
324
+ fileUri: content.image.url,
325
+ mimeType: content.mediaType ?? mimeTypeFromImageUrl(content.image.url)
370
326
  }
371
327
  };
372
328
  }
@@ -388,29 +344,29 @@ function safeUrlPathname(url) {
388
344
  }
389
345
  }
390
346
  function documentContentToGeminiPart(content) {
391
- if (content.source.type === "text") {
392
- return { text: content.source.text };
347
+ if (content.data.type === "text") {
348
+ return { text: content.data.text };
393
349
  }
394
- if (content.source.type === "base64") {
350
+ if (content.data.type === "data") {
395
351
  return {
396
352
  inlineData: {
397
- mimeType: content.source.mediaType,
398
- data: content.source.data
353
+ mimeType: content.mediaType,
354
+ data: content.data.data
399
355
  }
400
356
  };
401
357
  }
402
358
  return {
403
359
  fileData: {
404
- fileUri: content.source.url,
405
- mimeType: content.source.mediaType
360
+ fileUri: content.data.url,
361
+ mimeType: content.mediaType
406
362
  }
407
363
  };
408
364
  }
409
365
  function toolContentToGeminiPart(content, toolNamesById) {
410
- const id = content.callId ?? content.id;
366
+ const id = content.callId ?? content.toolCallId;
411
367
  const functionResponse = {
412
- name: content.toolName ?? toolNamesById.get(id) ?? content.id,
413
- response: toolResultResponse(content.content)
368
+ name: content.toolName || toolNamesById.get(id) || content.toolCallId,
369
+ response: toolResultResponse(content)
414
370
  };
415
371
  if (content.callId !== void 0) {
416
372
  functionResponse.id = content.callId;
@@ -418,10 +374,21 @@ function toolContentToGeminiPart(content, toolNamesById) {
418
374
  return { functionResponse };
419
375
  }
420
376
  function toolResultResponse(content) {
377
+ const output = content.output;
378
+ if (output.type === "json") {
379
+ return { result: output.value };
380
+ }
381
+ if (output.type === "text") {
382
+ return { content: output.value };
383
+ }
384
+ if (output.type === "error-json" || output.type === "error-text") {
385
+ return { error: output.value };
386
+ }
387
+ if (output.type === "execution-denied") {
388
+ return { error: output.reason ?? "Tool execution was denied." };
389
+ }
421
390
  return {
422
- content: content.map(
423
- (item) => item.type === "text" ? item.text : `[image:${item.mediaType ?? "image/png"}]`
424
- ).join("\n")
391
+ content: output.value.map((item) => item.type === "text" ? item.text : `[file:${item.mediaType}]`).join("\n")
425
392
  };
426
393
  }
427
394
  function toolDefinitionToGemini(tool) {
@@ -463,7 +430,7 @@ function fromGeminiGenerateContentResponse(response) {
463
430
  return result;
464
431
  }
465
432
  function fromGeminiGenerateContentStreamChunk(chunk) {
466
- if (!isPlainObject(chunk)) {
433
+ if (!isPlainObject2(chunk)) {
467
434
  return [];
468
435
  }
469
436
  const events = [];
@@ -500,7 +467,7 @@ function fromGeminiGenerateContentStreamChunk(chunk) {
500
467
  if (id !== void 0) {
501
468
  events.push({ type: "message_id", id });
502
469
  }
503
- if (isPlainObject(chunk.usageMetadata)) {
470
+ if (isPlainObject2(chunk.usageMetadata)) {
504
471
  events.push({ type: "final", response: fromGeminiGenerateContentResponse(chunk) });
505
472
  }
506
473
  return events;
@@ -509,34 +476,39 @@ function assistantContentFromGeminiResponse(response) {
509
476
  const parts = candidateParts(response);
510
477
  if (parts.length === 0) {
511
478
  const text = textFromGeminiResponse(response);
512
- return text.length > 0 ? [AssistantContent.text(text)] : [];
479
+ return text.length > 0 ? [{ type: "text", text }] : [];
513
480
  }
514
481
  const choice = [];
515
482
  for (const part of parts) {
516
483
  if (typeof part.text === "string" && part.text.length > 0) {
517
484
  if (part.thought === true) {
518
- choice.push(AssistantContent.reasoningSummary(part.text));
485
+ choice.push({
486
+ type: "reasoning",
487
+ text: part.text,
488
+ details: [{ type: "summary", text: part.text }]
489
+ });
519
490
  } else {
520
- const text = AssistantContent.text(part.text);
521
491
  const signature = thoughtSignatureFrom(part);
522
- if (signature !== void 0) {
523
- text.signature = signature;
524
- }
492
+ let text = {
493
+ type: "text",
494
+ text: part.text
495
+ };
496
+ if (signature !== void 0) text = { ...text, signature };
525
497
  choice.push(text);
526
498
  }
527
499
  }
528
- if (isPlainObject(part.functionCall)) {
500
+ if (isPlainObject2(part.functionCall)) {
529
501
  const call = functionCallFromGeminiPart(part.functionCall, part);
530
502
  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
- }
503
+ const toolCallId = call.id ?? crypto.randomUUID();
504
+ let toolCall = {
505
+ type: "tool-call",
506
+ toolCallId,
507
+ toolName: call.name,
508
+ input: call.args
509
+ };
510
+ if (call.id !== void 0) toolCall = { ...toolCall, callId: call.id };
511
+ if (call.signature !== void 0) toolCall = { ...toolCall, signature: call.signature };
540
512
  choice.push(toolCall);
541
513
  }
542
514
  }
@@ -552,14 +524,14 @@ function textFromGeminiResponse(response) {
552
524
  function functionCallsFromGeminiResponse(response) {
553
525
  const directCalls = Array.isArray(response.functionCalls) ? response.functionCalls : Array.isArray(response.function_calls) ? response.function_calls : [];
554
526
  const partCalls = candidateParts(response).flatMap((part) => {
555
- if (!isPlainObject(part.functionCall)) {
527
+ if (!isPlainObject2(part.functionCall)) {
556
528
  return [];
557
529
  }
558
530
  const call = functionCallFromGeminiPart(part.functionCall, part);
559
531
  return call === void 0 ? [] : [call];
560
532
  });
561
533
  const normalizedDirectCalls = directCalls.flatMap((call) => {
562
- if (!isPlainObject(call) || typeof call.name !== "string") {
534
+ if (!isPlainObject2(call) || typeof call.name !== "string") {
563
535
  return [];
564
536
  }
565
537
  const normalized = {
@@ -599,14 +571,14 @@ function functionCallFromGeminiPart(call, part) {
599
571
  function candidateParts(response) {
600
572
  const candidates = Array.isArray(response.candidates) ? response.candidates : [];
601
573
  return candidates.flatMap((candidate) => {
602
- if (!isPlainObject(candidate) || !isPlainObject(candidate.content)) {
574
+ if (!isPlainObject2(candidate) || !isPlainObject2(candidate.content)) {
603
575
  return [];
604
576
  }
605
- return Array.isArray(candidate.content.parts) ? candidate.content.parts.filter(isPlainObject) : [];
577
+ return Array.isArray(candidate.content.parts) ? candidate.content.parts.filter(isPlainObject2) : [];
606
578
  });
607
579
  }
608
580
  function usageFromGemini(usage) {
609
- const raw = isPlainObject(usage) ? usage : {};
581
+ const raw = isPlainObject2(usage) ? usage : {};
610
582
  const promptInputTokens = numberFrom(raw.promptTokenCount);
611
583
  const toolInputTokens = numberFrom(raw.toolUsePromptTokenCount);
612
584
  const inputTokens = promptInputTokens + toolInputTokens;
@@ -632,12 +604,12 @@ function usageFromGemini(usage) {
632
604
  };
633
605
  }
634
606
  function toJsonValue(value) {
635
- if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || Array.isArray(value) || isPlainObject(value)) {
607
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || Array.isArray(value) || isPlainObject2(value)) {
636
608
  return value;
637
609
  }
638
610
  return String(value);
639
611
  }
640
- function isPlainObject(value) {
612
+ function isPlainObject2(value) {
641
613
  return typeof value === "object" && value !== null && !Array.isArray(value);
642
614
  }
643
615
  function numberFrom(value) {
@@ -661,36 +633,41 @@ function toolCallDelta(id, values) {
661
633
 
662
634
  // src/gemini/embedding.ts
663
635
  var GeminiEmbeddingModel = class {
664
- constructor(client, model, options = {}) {
636
+ constructor(client, options) {
665
637
  this.client = client;
666
- this.model = model;
638
+ this.modelId = options.modelId;
667
639
  this.dimensions = options.dimensions;
668
640
  this.maxBatchSize = options.maxBatchSize ?? 100;
669
641
  this.taskType = options.taskType;
670
642
  this.title = options.title;
671
643
  }
672
644
  client;
673
- model;
645
+ provider = "gemini";
646
+ modelId;
674
647
  dimensions;
675
648
  maxBatchSize;
676
649
  taskType;
677
650
  title;
678
- async embedTexts(texts) {
651
+ async embedTexts(texts, options) {
679
652
  const embeddings = [];
680
653
  for (let index = 0; index < texts.length; index += this.maxBatchSize) {
681
654
  const batch = texts.slice(index, index + this.maxBatchSize);
682
- embeddings.push(...await this.embedBatch(batch));
655
+ embeddings.push(...await this.embedBatch(batch, options));
683
656
  }
684
657
  return embeddings;
685
658
  }
686
- async embedBatch(texts) {
659
+ async embedBatch(texts, options) {
687
660
  if (texts.length === 0) {
688
661
  return [];
689
662
  }
663
+ const config = { ...this.embeddingConfig() };
664
+ if (options?.abortSignal !== void 0) {
665
+ Object.assign(config, { abortSignal: options.abortSignal });
666
+ }
690
667
  const response = await this.client.models.embedContent({
691
- model: this.model,
668
+ model: this.modelId,
692
669
  contents: texts,
693
- config: this.embeddingConfig()
670
+ config: disableGeminiNativeRetries(config)
694
671
  });
695
672
  const rawEmbeddings = embeddingsFromResponse(response);
696
673
  if (rawEmbeddings.length !== texts.length) {
@@ -740,54 +717,60 @@ var GEMINI_2_5_FLASH_IMAGE = "gemini-2.5-flash-image";
740
717
  var GEMINI_3_PRO_IMAGE_PREVIEW = "gemini-3-pro-image-preview";
741
718
  var IMAGEN_4_GENERATE = "imagen-4.0-generate-001";
742
719
  var GeminiImageGenerationModel = class {
743
- constructor(client, defaultModel = GEMINI_2_5_FLASH_IMAGE) {
720
+ constructor(client, modelId) {
744
721
  this.client = client;
745
- this.defaultModel = defaultModel;
722
+ this.modelId = modelId;
746
723
  }
747
724
  client;
748
- defaultModel;
725
+ modelId;
749
726
  provider = "gemini";
750
- async imageGeneration(request) {
727
+ async imageGeneration(request, options) {
728
+ const providerOptions = isPlainObject3(request.providerOptions) ? request.providerOptions : {};
729
+ const { config: providerConfigValue, ...providerTopLevel } = providerOptions;
730
+ const providerConfig = isPlainObject3(providerConfigValue) ? providerConfigValue : {};
731
+ const providerImageConfig = isPlainObject3(providerConfig.imageConfig) ? providerConfig.imageConfig : {};
732
+ const config = {
733
+ ...providerConfig,
734
+ responseModalities: ["TEXT", "IMAGE"],
735
+ imageConfig: {
736
+ ...providerImageConfig,
737
+ aspectRatio: aspectRatio(request.width, request.height)
738
+ }
739
+ };
740
+ if (options?.abortSignal !== void 0) config.abortSignal = options.abortSignal;
751
741
  const params = {
752
- model: this.defaultModel,
742
+ ...providerTopLevel,
743
+ model: this.modelId,
753
744
  contents: request.prompt,
754
- config: {
755
- responseModalities: ["TEXT", "IMAGE"],
756
- imageConfig: { aspectRatio: aspectRatio(request.width, request.height) }
757
- }
745
+ config: disableGeminiNativeRetries(config)
758
746
  };
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
747
  const response = await this.client.models.generateContent(params);
767
748
  return nativeImageResponseFromGemini(response);
768
749
  }
769
750
  };
770
751
  var GeminiImagenGenerationModel = class {
771
- constructor(client, defaultModel = IMAGEN_4_GENERATE) {
752
+ constructor(client, modelId) {
772
753
  this.client = client;
773
- this.defaultModel = defaultModel;
754
+ this.modelId = modelId;
774
755
  }
775
756
  client;
776
- defaultModel;
757
+ modelId;
777
758
  provider = "gemini";
778
- async imageGeneration(request) {
759
+ async imageGeneration(request, options) {
760
+ const providerOptions = isPlainObject3(request.providerOptions) ? request.providerOptions : {};
761
+ const { config: providerConfigValue, ...providerTopLevel } = providerOptions;
762
+ const providerConfig = isPlainObject3(providerConfigValue) ? providerConfigValue : {};
763
+ const config = {
764
+ ...providerConfig,
765
+ aspectRatio: aspectRatio(request.width, request.height)
766
+ };
767
+ if (options?.abortSignal !== void 0) config.abortSignal = options.abortSignal;
779
768
  const params = {
780
- model: this.defaultModel,
769
+ ...providerTopLevel,
770
+ model: this.modelId,
781
771
  prompt: request.prompt,
782
- config: { aspectRatio: aspectRatio(request.width, request.height) }
772
+ config: disableGeminiNativeRetries(config)
783
773
  };
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
774
  const response = await this.client.models.generateImages(params);
792
775
  return imagenResponseFromGemini(response);
793
776
  }
@@ -796,12 +779,12 @@ function nativeImageResponseFromGemini(response) {
796
779
  const raw = response;
797
780
  const candidates = Array.isArray(raw.candidates) ? raw.candidates : [];
798
781
  const images = candidates.flatMap((candidate) => {
799
- if (!isPlainObject2(candidate) || !isPlainObject2(candidate.content)) {
782
+ if (!isPlainObject3(candidate) || !isPlainObject3(candidate.content)) {
800
783
  return [];
801
784
  }
802
785
  const parts = Array.isArray(candidate.content.parts) ? candidate.content.parts : [];
803
786
  return parts.flatMap((part) => {
804
- if (!isPlainObject2(part) || !isPlainObject2(part.inlineData)) {
787
+ if (!isPlainObject3(part) || !isPlainObject3(part.inlineData)) {
805
788
  return [];
806
789
  }
807
790
  const data = part.inlineData.data;
@@ -816,14 +799,11 @@ function nativeImageResponseFromGemini(response) {
816
799
  ];
817
800
  });
818
801
  });
819
- const image = images[0]?.data;
820
- if (image === void 0) {
802
+ if (images.length === 0) {
821
803
  throw new Error("Gemini image generation response contained no inline image data.");
822
804
  }
823
805
  return {
824
- image,
825
806
  images,
826
- mediaType: images[0]?.mediaType,
827
807
  rawResponse: response
828
808
  };
829
809
  }
@@ -831,7 +811,7 @@ function imagenResponseFromGemini(response) {
831
811
  const raw = response;
832
812
  const images = (Array.isArray(raw.generatedImages) ? raw.generatedImages : []).flatMap(
833
813
  (item) => {
834
- if (!isPlainObject2(item) || !isPlainObject2(item.image)) {
814
+ if (!isPlainObject3(item) || !isPlainObject3(item.image)) {
835
815
  return [];
836
816
  }
837
817
  const imageBytes = item.image.imageBytes;
@@ -846,14 +826,11 @@ function imagenResponseFromGemini(response) {
846
826
  ];
847
827
  }
848
828
  );
849
- const image = images[0]?.data;
850
- if (image === void 0) {
829
+ if (images.length === 0) {
851
830
  throw new Error("Gemini image generation response contained no base64 images.");
852
831
  }
853
832
  return {
854
- image,
855
833
  images,
856
- mediaType: images[0]?.mediaType,
857
834
  rawResponse: response
858
835
  };
859
836
  }
@@ -882,50 +859,114 @@ function decodeBase64Image(value) {
882
859
  }
883
860
  return new Uint8Array(bytes);
884
861
  }
885
- function isPlainObject2(value) {
862
+ function isPlainObject3(value) {
886
863
  return typeof value === "object" && value !== null && !Array.isArray(value);
887
864
  }
888
865
 
866
+ // src/gemini/models.ts
867
+ var CONTEXT_1M_64K = {
868
+ contextWindow: 1048576,
869
+ maxInputTokens: 1048576,
870
+ maxOutputTokens: 65536
871
+ };
872
+ var GEMINI_COMPLETION_MODEL_CONTEXT_LIMITS = {
873
+ "gemini-2.0-flash": {
874
+ contextWindow: 1048576,
875
+ maxInputTokens: 1048576,
876
+ maxOutputTokens: 8192
877
+ },
878
+ "gemini-2.0-flash-lite": {
879
+ contextWindow: 1048576,
880
+ maxInputTokens: 1048576,
881
+ maxOutputTokens: 8192
882
+ },
883
+ "gemini-2.5-flash": CONTEXT_1M_64K,
884
+ "gemini-2.5-flash-image": {
885
+ contextWindow: 32768,
886
+ maxInputTokens: 32768,
887
+ maxOutputTokens: 32768
888
+ },
889
+ "gemini-2.5-flash-lite": CONTEXT_1M_64K,
890
+ "gemini-2.5-flash-preview-tts": {
891
+ contextWindow: 8192,
892
+ maxInputTokens: 8192,
893
+ maxOutputTokens: 16384
894
+ },
895
+ "gemini-2.5-pro": CONTEXT_1M_64K,
896
+ "gemini-2.5-pro-preview-tts": {
897
+ contextWindow: 8192,
898
+ maxInputTokens: 8192,
899
+ maxOutputTokens: 16384
900
+ },
901
+ "gemini-3-flash-preview": CONTEXT_1M_64K,
902
+ "gemini-3-pro-image-preview": {
903
+ contextWindow: 131072,
904
+ maxInputTokens: 131072,
905
+ maxOutputTokens: 32768
906
+ },
907
+ "gemini-3-pro-preview": CONTEXT_1M_64K,
908
+ "gemini-3.1-flash-image-preview": {
909
+ contextWindow: 65536,
910
+ maxInputTokens: 65536,
911
+ maxOutputTokens: 65536
912
+ },
913
+ "gemini-3.1-flash-lite": CONTEXT_1M_64K,
914
+ "gemini-3.1-flash-lite-preview": CONTEXT_1M_64K,
915
+ "gemini-3.1-pro-preview": CONTEXT_1M_64K,
916
+ "gemini-3.1-pro-preview-customtools": CONTEXT_1M_64K,
917
+ "gemini-3.5-flash": CONTEXT_1M_64K,
918
+ "gemini-flash-latest": CONTEXT_1M_64K,
919
+ "gemini-flash-lite-latest": CONTEXT_1M_64K,
920
+ "gemma-4-26b-a4b-it": {
921
+ contextWindow: 262144,
922
+ maxInputTokens: 262144,
923
+ maxOutputTokens: 32768
924
+ },
925
+ "gemma-4-31b-it": {
926
+ contextWindow: 262144,
927
+ maxInputTokens: 262144,
928
+ maxOutputTokens: 32768
929
+ }
930
+ };
931
+
889
932
  // src/gemini/transcription.ts
890
933
  import { Buffer as Buffer3 } from "buffer";
891
934
  var TRANSCRIPTION_PREAMBLE = "Transcribe the provided audio exactly. Do not add additional information.";
892
935
  var GeminiTranscriptionModel = class {
893
- constructor(client, defaultModel = "gemini-2.5-flash") {
936
+ constructor(client, modelId) {
894
937
  this.client = client;
895
- this.defaultModel = defaultModel;
938
+ this.modelId = modelId;
896
939
  }
897
940
  client;
898
- defaultModel;
941
+ modelId;
899
942
  provider = "gemini";
900
- async transcription(request) {
901
- const config = {};
943
+ async transcription(request, options) {
944
+ const config = isPlainObject4(request.providerOptions) ? { ...request.providerOptions } : {};
902
945
  if (request.temperature !== void 0) {
903
946
  config.temperature = request.temperature;
904
947
  }
905
- if (isPlainObject3(request.additionalParams)) {
906
- Object.assign(config, request.additionalParams);
907
- }
948
+ if (options?.abortSignal !== void 0) config.abortSignal = options.abortSignal;
908
949
  const response = await this.client.models.generateContent({
909
- model: this.defaultModel,
950
+ model: this.modelId,
910
951
  contents: [
911
952
  {
912
953
  role: "user",
913
954
  parts: [
914
955
  {
915
956
  inlineData: {
916
- mimeType: mimeTypeFromFilename(request.filename),
957
+ mimeType: request.mediaType ?? mimeTypeFromFilename(request.filename),
917
958
  data: Buffer3.from(request.data).toString("base64")
918
959
  }
919
960
  }
920
961
  ]
921
962
  }
922
963
  ],
923
- config: {
964
+ config: disableGeminiNativeRetries({
924
965
  ...config,
925
966
  systemInstruction: request.prompt === void 0 ? TRANSCRIPTION_PREAMBLE : `${TRANSCRIPTION_PREAMBLE}
926
967
 
927
968
  ${request.prompt}`
928
- }
969
+ })
929
970
  });
930
971
  return {
931
972
  text: textFromGenerateContentResponse(response),
@@ -940,12 +981,12 @@ function textFromGenerateContentResponse(response) {
940
981
  }
941
982
  const candidates = Array.isArray(raw.candidates) ? raw.candidates : [];
942
983
  for (const candidate of candidates) {
943
- if (!isPlainObject3(candidate) || !isPlainObject3(candidate.content)) {
984
+ if (!isPlainObject4(candidate) || !isPlainObject4(candidate.content)) {
944
985
  continue;
945
986
  }
946
987
  const parts = Array.isArray(candidate.content.parts) ? candidate.content.parts : [];
947
988
  for (const part of parts) {
948
- if (isPlainObject3(part) && typeof part.text === "string") {
989
+ if (isPlainObject4(part) && typeof part.text === "string") {
949
990
  return part.text;
950
991
  }
951
992
  }
@@ -962,34 +1003,55 @@ function mimeTypeFromFilename(filename) {
962
1003
  if (lower.endsWith(".opus")) return "audio/opus";
963
1004
  return "audio/mpeg";
964
1005
  }
965
- function isPlainObject3(value) {
1006
+ function isPlainObject4(value) {
966
1007
  return typeof value === "object" && value !== null && !Array.isArray(value);
967
1008
  }
968
1009
 
969
1010
  // src/gemini/client.ts
970
1011
  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);
1012
+ sdk;
1013
+ constructor(options) {
1014
+ if (options.client !== void 0) {
1015
+ rejectManagedOptionsWithInjectedClient(options, ["apiKey", "vertexAi"]);
1016
+ this.sdk = options.client;
1017
+ return;
1018
+ }
1019
+ this.sdk = new GoogleGenAI(toGoogleGenAIOptions(options));
1020
+ }
1021
+ completionModel(options) {
1022
+ const modelId = requireModelId(options.modelId);
1023
+ return new GeminiCompletionModel(
1024
+ this.sdk,
1025
+ modelId,
1026
+ resolveModelContextLimits(
1027
+ modelId,
1028
+ GEMINI_COMPLETION_MODEL_CONTEXT_LIMITS,
1029
+ options.contextLimits
1030
+ )
1031
+ );
980
1032
  }
981
- imageGenerationModel(model = GEMINI_2_5_FLASH_IMAGE) {
982
- return new GeminiImageGenerationModel(this.client, model);
1033
+ embeddingModel(options) {
1034
+ requireModelId(options.modelId);
1035
+ validateOptionalPositiveSafeInteger(options.dimensions, "dimensions");
1036
+ validateOptionalPositiveSafeInteger(options.maxBatchSize, "maxBatchSize");
1037
+ return new GeminiEmbeddingModel(this.sdk, options);
983
1038
  }
984
- imagenGenerationModel(model = IMAGEN_4_GENERATE) {
985
- return new GeminiImagenGenerationModel(this.client, model);
1039
+ imageGenerationModel(options) {
1040
+ const modelId = requireModelId(options.modelId);
1041
+ return options.api === "generateContent" ? new GeminiImageGenerationModel(this.sdk, modelId) : new GeminiImagenGenerationModel(this.sdk, modelId);
986
1042
  }
987
- transcriptionModel(model = "gemini-2.5-flash") {
988
- return new GeminiTranscriptionModel(this.client, model);
1043
+ transcriptionModel(options) {
1044
+ return new GeminiTranscriptionModel(this.sdk, requireModelId(options.modelId));
989
1045
  }
990
- async listModels() {
1046
+ async listModels(options = {}) {
991
1047
  try {
992
- const response = await this.client.models.list({ config: { pageSize: 1e3 } });
1048
+ const config = { pageSize: 1e3 };
1049
+ if (options.abortSignal !== void 0) {
1050
+ Object.assign(config, { abortSignal: options.abortSignal });
1051
+ }
1052
+ const response = await this.sdk.models.list({
1053
+ config: disableGeminiNativeRetries(config)
1054
+ });
993
1055
  const data = (await collectModelsFromResponse(response)).map(toListedModel).filter(isListedModel);
994
1056
  return { data };
995
1057
  } catch (error) {
@@ -997,25 +1059,48 @@ var GeminiClient = class {
997
1059
  }
998
1060
  }
999
1061
  };
1062
+ function rejectManagedOptionsWithInjectedClient(options, keys) {
1063
+ const conflict = keys.find((key) => key in options);
1064
+ if (conflict !== void 0) {
1065
+ throw new TypeError(`GeminiClient cannot combine client with ${conflict}.`);
1066
+ }
1067
+ }
1000
1068
  function toGoogleGenAIOptions(options) {
1001
- if (options.vertexai === true) {
1002
- return {
1069
+ if ("client" in options && options.client !== void 0) {
1070
+ throw new TypeError("Injected Gemini clients do not have managed SDK options.");
1071
+ }
1072
+ if ("vertexAi" in options && options.vertexAi !== void 0) {
1073
+ const sdkOptions = {
1003
1074
  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 }
1075
+ project: requireOption(options.vertexAi.projectId, "projectId", "Vertex Gemini"),
1076
+ location: requireOption(options.vertexAi.location, "location", "Vertex Gemini")
1007
1077
  };
1078
+ if (options.vertexAi.googleAuthOptions !== void 0) {
1079
+ sdkOptions.googleAuthOptions = options.vertexAi.googleAuthOptions;
1080
+ }
1081
+ return sdkOptions;
1008
1082
  }
1009
1083
  return {
1010
1084
  apiKey: requireOption(options.apiKey, "apiKey", "Gemini")
1011
1085
  };
1012
1086
  }
1013
1087
  function requireOption(value, name, label) {
1014
- if (value === void 0 || value.length === 0) {
1088
+ if (value === void 0 || value.trim().length === 0) {
1015
1089
  throw new Error(`Missing ${label} ${name}. Pass ${name} when constructing GeminiClient.`);
1016
1090
  }
1017
1091
  return value;
1018
1092
  }
1093
+ function requireModelId(modelId) {
1094
+ if (modelId.trim().length === 0) {
1095
+ throw new TypeError("modelId must be a non-empty string");
1096
+ }
1097
+ return modelId;
1098
+ }
1099
+ function validateOptionalPositiveSafeInteger(value, name) {
1100
+ if (value !== void 0 && (!Number.isSafeInteger(value) || value <= 0)) {
1101
+ throw new TypeError(`${name} must be a positive safe integer`);
1102
+ }
1103
+ }
1019
1104
  async function collectModelsFromResponse(response) {
1020
1105
  if (isAsyncIterable(response)) {
1021
1106
  const models = [];
@@ -1116,11 +1201,6 @@ export {
1116
1201
  GEMINI_2_5_FLASH_IMAGE,
1117
1202
  GEMINI_3_PRO_IMAGE_PREVIEW,
1118
1203
  GeminiClient,
1119
- GeminiCompletionModel,
1120
- GeminiEmbeddingModel,
1121
- GeminiImageGenerationModel,
1122
- GeminiImagenGenerationModel,
1123
- GeminiTranscriptionModel,
1124
1204
  IMAGEN_4_GENERATE,
1125
1205
  gemini_exports as gemini
1126
1206
  };