@ai-sdk/google 4.0.51 → 4.0.54

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
@@ -7,7 +7,7 @@ import {
7
7
  } from "@ai-sdk/provider-utils";
8
8
 
9
9
  // src/version.ts
10
- var VERSION = true ? "4.0.51" : "0.0.0-test";
10
+ var VERSION = true ? "4.0.54" : "0.0.0-test";
11
11
 
12
12
  // src/google-embedding-model.ts
13
13
  import {
@@ -253,18 +253,18 @@ var googleGenerativeAISingleEmbeddingResponseSchema = lazySchema3(
253
253
 
254
254
  // src/google-batch.ts
255
255
  import {
256
- EmptyResponseBodyError,
257
256
  InvalidArgumentError,
258
257
  InvalidResponseDataError
259
258
  } from "@ai-sdk/provider";
260
259
  import {
261
260
  combineHeaders as combineHeaders3,
262
261
  convertAsyncIteratorToReadableStream,
262
+ createJsonLinesResponseHandler,
263
263
  createJsonResponseHandler as createJsonResponseHandler3,
264
264
  generateId as generateId2,
265
265
  getFromApi,
266
266
  lazySchema as lazySchema6,
267
- parseJSON,
267
+ normalizeBatchRequestCounts,
268
268
  postJsonToApi as postJsonToApi3,
269
269
  postToApi,
270
270
  resolve as resolve3,
@@ -331,6 +331,10 @@ function convertGoogleUsage(usage) {
331
331
  import {
332
332
  UnsupportedFunctionalityError
333
333
  } from "@ai-sdk/provider";
334
+ var recursiveReferenceFunctionalityPrefix = "recursive JSON Schema reference:";
335
+ function isRecursiveJSONSchemaReferenceError(error) {
336
+ return UnsupportedFunctionalityError.isInstance(error) && error.functionality.startsWith(recursiveReferenceFunctionalityPrefix);
337
+ }
334
338
  function convertJSONSchemaToOpenAPISchema(jsonSchema, isRoot = true) {
335
339
  const rootSchema = typeof jsonSchema === "object" ? jsonSchema : void 0;
336
340
  return convertJSONSchemaDefinition(jsonSchema, isRoot, {
@@ -471,7 +475,7 @@ function convertJSONSchemaReference({
471
475
  );
472
476
  if (referenceContext.resolvingReferences.has(referenceKey)) {
473
477
  throw new UnsupportedFunctionalityError({
474
- functionality: `recursive JSON Schema reference: ${reference}`,
478
+ functionality: `${recursiveReferenceFunctionalityPrefix} ${reference}`,
475
479
  message: "Google schema conversion does not support recursive JSON Schema references."
476
480
  });
477
481
  }
@@ -1278,7 +1282,6 @@ function prepareTools({
1278
1282
  modelId,
1279
1283
  isVertexProvider = false
1280
1284
  }) {
1281
- var _a, _b;
1282
1285
  tools = (tools == null ? void 0 : tools.length) ? tools : void 0;
1283
1286
  const toolWarnings = [];
1284
1287
  const { supportsGemini2Tools, supportsFileSearch, usesGemini3Features } = getGoogleModelCapabilities(modelId);
@@ -1396,11 +1399,7 @@ function prepareTools({
1396
1399
  const functionDeclarations2 = [];
1397
1400
  for (const tool of tools) {
1398
1401
  if (tool.type === "function") {
1399
- functionDeclarations2.push({
1400
- name: tool.name,
1401
- description: (_a = tool.description) != null ? _a : "",
1402
- parameters: convertJSONSchemaToOpenAPISchema(tool.inputSchema)
1403
- });
1402
+ functionDeclarations2.push(prepareFunctionDeclaration(tool));
1404
1403
  }
1405
1404
  }
1406
1405
  const combinedToolConfig = {
@@ -1444,11 +1443,7 @@ function prepareTools({
1444
1443
  for (const tool of tools) {
1445
1444
  switch (tool.type) {
1446
1445
  case "function":
1447
- functionDeclarations.push({
1448
- name: tool.name,
1449
- description: (_b = tool.description) != null ? _b : "",
1450
- parameters: convertJSONSchemaToOpenAPISchema(tool.inputSchema)
1451
- });
1446
+ functionDeclarations.push(prepareFunctionDeclaration(tool));
1452
1447
  if (tool.strict === true) {
1453
1448
  hasStrictTools = true;
1454
1449
  }
@@ -1515,6 +1510,27 @@ function prepareTools({
1515
1510
  }
1516
1511
  }
1517
1512
  }
1513
+ function prepareFunctionDeclaration(tool) {
1514
+ var _a;
1515
+ const declaration = {
1516
+ name: tool.name,
1517
+ description: (_a = tool.description) != null ? _a : ""
1518
+ };
1519
+ try {
1520
+ return {
1521
+ ...declaration,
1522
+ parameters: convertJSONSchemaToOpenAPISchema(tool.inputSchema)
1523
+ };
1524
+ } catch (error) {
1525
+ if (!isRecursiveJSONSchemaReferenceError(error)) {
1526
+ throw error;
1527
+ }
1528
+ return {
1529
+ ...declaration,
1530
+ parametersJsonSchema: tool.inputSchema
1531
+ };
1532
+ }
1533
+ }
1518
1534
 
1519
1535
  // src/google-json-accumulator.ts
1520
1536
  var GoogleJSONAccumulator = class {
@@ -3254,17 +3270,19 @@ var GoogleBatchLanguageModel = class _GoogleBatchLanguageModel extends GoogleLan
3254
3270
  });
3255
3271
  }
3256
3272
  const encodedResponsesFile = responsesFile.split("/").map((segment) => encodeURIComponent(segment)).join("/");
3257
- const { value: stream } = await getFromApi({
3273
+ const { value: lines } = await getFromApi({
3258
3274
  url: `${this.getBaseOrigin()}/download/v1beta/${encodedResponsesFile}:download?alt=media`,
3259
3275
  headers: await this.getHeaders(options.headers),
3260
3276
  failedResponseHandler: googleFailedResponseHandler,
3261
- successfulResponseHandler: rawStreamResponseHandler,
3277
+ successfulResponseHandler: createJsonLinesResponseHandler(
3278
+ googleBatchResultLineSchema
3279
+ ),
3262
3280
  abortSignal: options.abortSignal,
3263
3281
  fetch: this.batchConfig.fetch,
3264
3282
  validateUrl: false
3265
3283
  });
3266
3284
  return convertAsyncIteratorToReadableStream(
3267
- this.iterateBatchResults(parseJsonLines(stream))
3285
+ this.iterateBatchResults(lines)
3268
3286
  );
3269
3287
  }
3270
3288
  async retrieveBatch(options) {
@@ -3430,15 +3448,12 @@ function convertGoogleRequestCounts(counts) {
3430
3448
  const completed = parseCount((_a = counts == null ? void 0 : counts.successfulRequestCount) != null ? _a : 0);
3431
3449
  const failed = parseCount((_b = counts == null ? void 0 : counts.failedRequestCount) != null ? _b : 0);
3432
3450
  const pending = parseCount((_c = counts == null ? void 0 : counts.pendingRequestCount) != null ? _c : 0);
3433
- if (total == null || completed == null || failed == null || pending == null || completed + failed + pending !== total) {
3434
- return void 0;
3435
- }
3436
- return {
3451
+ return normalizeBatchRequestCounts({
3437
3452
  total,
3438
3453
  pending,
3439
3454
  completed,
3440
3455
  failed
3441
- };
3456
+ });
3442
3457
  }
3443
3458
  function parseCount(value) {
3444
3459
  const count = typeof value === "string" && /^\d+$/.test(value) ? Number(value) : value;
@@ -3464,54 +3479,6 @@ var googleUploadUrlResponseHandler = async ({
3464
3479
  }
3465
3480
  return { value: uploadUrl };
3466
3481
  };
3467
- var rawStreamResponseHandler = async ({ response }) => {
3468
- if (response.body == null) {
3469
- throw new EmptyResponseBodyError();
3470
- }
3471
- return { value: response.body };
3472
- };
3473
- async function* parseJsonLines(stream) {
3474
- const reader = stream.getReader();
3475
- const decoder = new TextDecoder();
3476
- let buffer = "";
3477
- let finished = false;
3478
- try {
3479
- while (true) {
3480
- const { done, value } = await reader.read();
3481
- if (done) {
3482
- finished = true;
3483
- buffer += decoder.decode();
3484
- break;
3485
- }
3486
- buffer += decoder.decode(value, { stream: true });
3487
- let lineEnd = buffer.indexOf("\n");
3488
- while (lineEnd !== -1) {
3489
- const line = buffer.slice(0, lineEnd).replace(/\r$/, "");
3490
- buffer = buffer.slice(lineEnd + 1);
3491
- if (line.trim().length > 0) {
3492
- yield await parseJSON({
3493
- text: line,
3494
- schema: googleBatchResultLineSchema
3495
- });
3496
- }
3497
- lineEnd = buffer.indexOf("\n");
3498
- }
3499
- }
3500
- const finalLine = buffer.replace(/\r$/, "");
3501
- if (finalLine.trim().length > 0) {
3502
- yield await parseJSON({
3503
- text: finalLine,
3504
- schema: googleBatchResultLineSchema
3505
- });
3506
- }
3507
- } finally {
3508
- if (!finished) {
3509
- await reader.cancel().catch(() => {
3510
- });
3511
- }
3512
- reader.releaseLock();
3513
- }
3514
- }
3515
3482
 
3516
3483
  // src/tool/code-execution.ts
3517
3484
  import { createProviderExecutedToolFactory } from "@ai-sdk/provider-utils";
@@ -3902,6 +3869,10 @@ import {
3902
3869
  getFromApi as getFromApi2
3903
3870
  } from "@ai-sdk/provider-utils";
3904
3871
  import { z as z15 } from "zod/v4";
3872
+ function encodePathSegment(value) {
3873
+ const encodedValue = encodeURIComponent(value);
3874
+ return encodedValue === "." ? "%252E" : encodedValue === ".." ? "%252E%252E" : encodedValue;
3875
+ }
3905
3876
  var GoogleFiles = class {
3906
3877
  constructor(config) {
3907
3878
  this.config = config;
@@ -3963,7 +3934,7 @@ var GoogleFiles = class {
3963
3934
  "X-Goog-Upload-Offset": "0",
3964
3935
  "X-Goog-Upload-Command": "upload, finalize"
3965
3936
  },
3966
- body: fileBytes
3937
+ body: ensureArrayBufferBacked(fileBytes)
3967
3938
  });
3968
3939
  if (!uploadResponse.ok) {
3969
3940
  const errorBody = await uploadResponse.text();
@@ -3985,8 +3956,10 @@ var GoogleFiles = class {
3985
3956
  });
3986
3957
  }
3987
3958
  await delay(pollIntervalMs);
3959
+ const fileNameMatch = /^files\/([^/]+)$/.exec(file.name);
3960
+ const filePath = fileNameMatch != null ? `files/${encodePathSegment(fileNameMatch[1])}` : encodePathSegment(file.name);
3988
3961
  const { value: fileStatus } = await getFromApi2({
3989
- url: `${this.config.baseURL}/${file.name}`,
3962
+ url: `${this.config.baseURL}/${filePath}`,
3990
3963
  validateUrl: false,
3991
3964
  headers: combineHeaders4(resolvedHeaders),
3992
3965
  successfulResponseHandler: createJsonResponseHandler4(
@@ -4024,6 +3997,12 @@ var GoogleFiles = class {
4024
3997
  };
4025
3998
  }
4026
3999
  };
4000
+ function ensureArrayBufferBacked(data) {
4001
+ if (data.buffer instanceof ArrayBuffer) {
4002
+ return data;
4003
+ }
4004
+ return new Uint8Array(data);
4005
+ }
4027
4006
  var googleFileResponseSchema = lazySchema14(
4028
4007
  () => zodSchema14(
4029
4008
  z15.object({
@@ -4683,6 +4662,11 @@ import {
4683
4662
  WORKFLOW_SERIALIZE as WORKFLOW_SERIALIZE6
4684
4663
  } from "@ai-sdk/provider-utils";
4685
4664
 
4665
+ // src/interactions/build-google-interactions-stream-transform.ts
4666
+ import {
4667
+ createProviderStreamError
4668
+ } from "@ai-sdk/provider-utils";
4669
+
4686
4670
  // src/interactions/convert-google-interactions-usage.ts
4687
4671
  import { createNullLanguageModelUsage as createNullLanguageModelUsage2 } from "@ai-sdk/provider-utils";
4688
4672
  function convertGoogleInteractionsUsage(usage) {
@@ -4977,7 +4961,7 @@ function buildGoogleInteractionsStreamTransform({
4977
4961
  controller.enqueue({ type: "stream-start", warnings });
4978
4962
  },
4979
4963
  transform(chunk, controller) {
4980
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
4964
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
4981
4965
  if (includeRawChunks) {
4982
4966
  controller.enqueue({ type: "raw", rawValue: chunk.rawValue });
4983
4967
  }
@@ -5388,10 +5372,15 @@ function buildGoogleInteractionsStreamTransform({
5388
5372
  case "error": {
5389
5373
  const event = value;
5390
5374
  finishStatus = "failed";
5391
- const errorPayload = (_q = event.error) != null ? _q : {
5392
- message: "Unknown interaction error"
5393
- };
5394
- controller.enqueue({ type: "error", error: errorPayload });
5375
+ controller.enqueue({
5376
+ type: "error",
5377
+ error: createProviderStreamError({
5378
+ message: (_r = (_q = event.error) == null ? void 0 : _q.message) != null ? _r : "Unknown interaction error",
5379
+ type: event.event_type,
5380
+ code: (_t = (_s = event.error) == null ? void 0 : _s.code) != null ? _t : void 0,
5381
+ data: event
5382
+ })
5383
+ });
5395
5384
  break;
5396
5385
  }
5397
5386
  default:
@@ -8014,21 +8003,538 @@ var GoogleRealtimeModel = class {
8014
8003
  }
8015
8004
  };
8016
8005
 
8017
- // src/speech-translation/google-speech-translation-model.ts
8006
+ // src/transcription/google-transcription-model.ts
8018
8007
  import {
8019
8008
  InvalidArgumentError as InvalidArgumentError2
8020
8009
  } from "@ai-sdk/provider";
8021
8010
  import {
8022
- connectToWebSocket,
8023
8011
  combineHeaders as combineHeaders9,
8024
- convertBase64ToUint8Array as convertBase64ToUint8Array2,
8012
+ connectToWebSocket,
8025
8013
  convertToBase64 as convertToBase644,
8014
+ createJsonResponseHandler as createJsonResponseHandler9,
8026
8015
  parseProviderOptions as parseProviderOptions8,
8016
+ postJsonToApi as postJsonToApi7,
8017
+ resolve as resolve7,
8027
8018
  safeParseJSON as safeParseJSON2,
8028
8019
  serializeModelOptions as serializeModelOptions6,
8020
+ waitForWebSocketBufferDrain,
8029
8021
  WORKFLOW_DESERIALIZE as WORKFLOW_DESERIALIZE7,
8030
- WORKFLOW_SERIALIZE as WORKFLOW_SERIALIZE7,
8031
- waitForWebSocketBufferDrain
8022
+ WORKFLOW_SERIALIZE as WORKFLOW_SERIALIZE7
8023
+ } from "@ai-sdk/provider-utils";
8024
+ import { z as z23 } from "zod/v4";
8025
+
8026
+ // src/transcription/google-transcription-model-options.ts
8027
+ import { z as z22 } from "zod/v4";
8028
+ var googleTranscriptionModelOptions = z22.object({
8029
+ /**
8030
+ * BCP-47 language codes providing hints about the languages present in the
8031
+ * audio. If omitted or empty, defaults to automatic language detection.
8032
+ */
8033
+ languageCodes: z22.array(z22.string()).optional(),
8034
+ /**
8035
+ * Custom vocabulary phrases, which bias the speech recognition model
8036
+ * toward recognizing specific terms.
8037
+ */
8038
+ customVocabulary: z22.array(z22.string()).optional(),
8039
+ /**
8040
+ * Enables word-level timestamp generation.
8041
+ */
8042
+ wordTimestamp: z22.boolean().optional(),
8043
+ /**
8044
+ * Enables speaker diarization.
8045
+ */
8046
+ diarization: z22.boolean().optional(),
8047
+ /**
8048
+ * Transcription output formatting mode.
8049
+ *
8050
+ * - `VERBATIM` (default): exact literal transcript preserving filler
8051
+ * words, repetitions, and false starts.
8052
+ * - `SMART`: cleans up and structures the transcript in real time —
8053
+ * disfluency removal, inline self-corrections, structured formatting
8054
+ * (lists, numbers, dates, paragraph breaks), and grammar/casing polish.
8055
+ */
8056
+ mode: z22.enum(["SMART", "VERBATIM"]).optional()
8057
+ });
8058
+
8059
+ // src/transcription/google-transcription-model.ts
8060
+ var liveWebSocketPath = "google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent";
8061
+ var defaultFinishGraceMs = 3e3;
8062
+ function getLiveWebSocketURL(baseURL, apiKey) {
8063
+ const url = getRealtimeWebSocketURL(baseURL, liveWebSocketPath);
8064
+ url.searchParams.set("key", apiKey);
8065
+ return url;
8066
+ }
8067
+ function isLiveTranscriptionModelId(modelId) {
8068
+ return modelId.includes("-live");
8069
+ }
8070
+ var GoogleTranscriptionModel = class _GoogleTranscriptionModel {
8071
+ constructor(modelId, config) {
8072
+ this.modelId = modelId;
8073
+ this.config = config;
8074
+ this.specificationVersion = "v4";
8075
+ }
8076
+ static [WORKFLOW_SERIALIZE7](model) {
8077
+ return serializeModelOptions6({
8078
+ modelId: model.modelId,
8079
+ config: model.config
8080
+ });
8081
+ }
8082
+ static [WORKFLOW_DESERIALIZE7](options) {
8083
+ return new _GoogleTranscriptionModel(options.modelId, options.config);
8084
+ }
8085
+ get provider() {
8086
+ return this.config.provider;
8087
+ }
8088
+ async parseOptions(providerOptions) {
8089
+ return parseProviderOptions8({
8090
+ provider: "google",
8091
+ providerOptions,
8092
+ schema: googleTranscriptionModelOptions
8093
+ });
8094
+ }
8095
+ async doGenerate(options) {
8096
+ var _a, _b, _c, _d, _e, _f;
8097
+ if (isLiveTranscriptionModelId(this.modelId)) {
8098
+ throw new InvalidArgumentError2({
8099
+ argument: "modelId",
8100
+ message: `Model '${this.modelId}' only supports streaming transcription. Use experimental_streamTranscribe, or a unary model such as 'gemini-3.5-transcribe'.`
8101
+ });
8102
+ }
8103
+ const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
8104
+ const warnings = [];
8105
+ const googleOptions = await this.parseOptions(options.providerOptions);
8106
+ const transcriptionConfig = buildTranscriptionConfig(googleOptions);
8107
+ const requestBody = {
8108
+ model: this.modelId,
8109
+ input: [
8110
+ {
8111
+ type: "audio",
8112
+ data: convertToBase644(options.audio),
8113
+ mime_type: options.mediaType
8114
+ }
8115
+ ],
8116
+ ...transcriptionConfig != null ? { generation_config: { transcription_config: transcriptionConfig } } : {}
8117
+ };
8118
+ const {
8119
+ value: response,
8120
+ responseHeaders,
8121
+ rawValue: rawResponse
8122
+ } = await postJsonToApi7({
8123
+ url: `${this.config.baseURL}/interactions`,
8124
+ headers: combineHeaders9(
8125
+ this.config.headers ? await resolve7(this.config.headers) : void 0,
8126
+ options.headers
8127
+ ),
8128
+ body: requestBody,
8129
+ failedResponseHandler: googleFailedResponseHandler,
8130
+ successfulResponseHandler: createJsonResponseHandler9(
8131
+ googleInteractionsTranscriptionResponseSchema
8132
+ ),
8133
+ abortSignal: options.abortSignal,
8134
+ fetch: this.config.fetch
8135
+ });
8136
+ let text = "";
8137
+ const segments = [];
8138
+ for (const step of (_d = response.steps) != null ? _d : []) {
8139
+ for (const content of (_e = step.content) != null ? _e : []) {
8140
+ if (content.type !== "text" || content.text == null) continue;
8141
+ text += content.text;
8142
+ for (const annotation of (_f = content.annotations) != null ? _f : []) {
8143
+ if (annotation.type !== "word_info") continue;
8144
+ const startSecond = parseOffsetSeconds(annotation.start_offset);
8145
+ const endSecond = parseOffsetSeconds(annotation.end_offset);
8146
+ if (annotation.text == null || startSecond == null || endSecond == null) {
8147
+ continue;
8148
+ }
8149
+ segments.push({ text: annotation.text, startSecond, endSecond });
8150
+ }
8151
+ }
8152
+ }
8153
+ return {
8154
+ text,
8155
+ segments,
8156
+ language: void 0,
8157
+ durationInSeconds: void 0,
8158
+ warnings,
8159
+ response: {
8160
+ timestamp: currentDate,
8161
+ modelId: this.modelId,
8162
+ headers: responseHeaders,
8163
+ body: rawResponse
8164
+ },
8165
+ ...response.usage != null ? {
8166
+ providerMetadata: {
8167
+ google: { usage: response.usage }
8168
+ }
8169
+ } : {}
8170
+ };
8171
+ }
8172
+ async doStream(options) {
8173
+ var _a, _b, _c, _d, _e, _f, _g;
8174
+ if (!isLiveTranscriptionModelId(this.modelId)) {
8175
+ throw new InvalidArgumentError2({
8176
+ argument: "modelId",
8177
+ message: `Model '${this.modelId}' does not support streaming transcription. Use a live model such as 'gemini-3.5-transcribe-live'.`
8178
+ });
8179
+ }
8180
+ const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
8181
+ const warnings = [];
8182
+ const googleOptions = await this.parseOptions(options.providerOptions);
8183
+ validateLiveInputAudioFormat(options.inputAudioFormat);
8184
+ const headers = combineHeaders9(
8185
+ this.config.headers ? await resolve7(this.config.headers) : void 0,
8186
+ options.headers
8187
+ );
8188
+ let apiKey;
8189
+ for (const [key, value] of Object.entries(headers)) {
8190
+ if (key.toLowerCase() === "x-goog-api-key" && value != null) {
8191
+ apiKey = value;
8192
+ }
8193
+ }
8194
+ if (apiKey == null) {
8195
+ throw new Error(
8196
+ "Google Generative AI API key is required for streaming transcription."
8197
+ );
8198
+ }
8199
+ const webSocketHeaders = Object.fromEntries(
8200
+ Object.entries(headers).filter(
8201
+ ([key]) => key.toLowerCase() !== "x-goog-api-key"
8202
+ )
8203
+ );
8204
+ const setup = {
8205
+ model: getModelPath(this.modelId),
8206
+ inputAudioTranscription: (_d = buildAudioTranscriptionConfig(googleOptions)) != null ? _d : {}
8207
+ };
8208
+ return {
8209
+ request: { body: setup },
8210
+ response: {
8211
+ timestamp: currentDate,
8212
+ modelId: this.modelId
8213
+ },
8214
+ stream: createGoogleLiveTranscriptionStream({
8215
+ webSocket: this.config.webSocket,
8216
+ url: getLiveWebSocketURL(this.config.baseURL, apiKey),
8217
+ headers: webSocketHeaders,
8218
+ setup,
8219
+ inputAudioRate: (_e = options.inputAudioFormat.rate) != null ? _e : 16e3,
8220
+ finishGraceMs: (_g = (_f = this.config._internal) == null ? void 0 : _f.finishGraceMs) != null ? _g : defaultFinishGraceMs,
8221
+ warnings,
8222
+ audio: options.audio,
8223
+ abortSignal: options.abortSignal,
8224
+ includeRawChunks: options.includeRawChunks
8225
+ })
8226
+ };
8227
+ }
8228
+ };
8229
+ function createGoogleLiveTranscriptionStream({
8230
+ webSocket,
8231
+ url,
8232
+ headers,
8233
+ setup,
8234
+ inputAudioRate,
8235
+ finishGraceMs,
8236
+ warnings,
8237
+ audio,
8238
+ abortSignal,
8239
+ includeRawChunks
8240
+ }) {
8241
+ let finished = false;
8242
+ let cleanup = () => {
8243
+ };
8244
+ return new ReadableStream({
8245
+ start: (controller) => {
8246
+ let audioReader;
8247
+ let connection;
8248
+ let resolveSetupComplete;
8249
+ const setupComplete = new Promise((resolve8) => {
8250
+ resolveSetupComplete = resolve8;
8251
+ });
8252
+ let segmentCounter = 0;
8253
+ let segmentBuffer = "";
8254
+ let fullText = "";
8255
+ let latestInterim = "";
8256
+ let language;
8257
+ let audioEnded = false;
8258
+ let usageMetadata;
8259
+ let finishTimer;
8260
+ const segmentId = () => `google-segment-${segmentCounter}`;
8261
+ const cancelPendingFinish = () => {
8262
+ if (finishTimer != null) {
8263
+ clearTimeout(finishTimer);
8264
+ finishTimer = void 0;
8265
+ }
8266
+ };
8267
+ const schedulePendingFinish = () => {
8268
+ if (finished || !audioEnded) return;
8269
+ cancelPendingFinish();
8270
+ finishTimer = setTimeout(() => {
8271
+ finishTimer = void 0;
8272
+ finish();
8273
+ }, finishGraceMs);
8274
+ };
8275
+ cleanup = (closeCode) => {
8276
+ cancelPendingFinish();
8277
+ if (audioReader != null) {
8278
+ void audioReader.cancel().catch(() => {
8279
+ });
8280
+ } else {
8281
+ void audio.cancel().catch(() => {
8282
+ });
8283
+ }
8284
+ connection == null ? void 0 : connection.close(closeCode);
8285
+ };
8286
+ const finishWithError = (error) => {
8287
+ if (finished) return;
8288
+ finished = true;
8289
+ cleanup();
8290
+ controller.error(error);
8291
+ };
8292
+ const completeSegment = () => {
8293
+ if (segmentBuffer === "") {
8294
+ if (latestInterim === "") return;
8295
+ segmentBuffer = latestInterim;
8296
+ }
8297
+ latestInterim = "";
8298
+ controller.enqueue({
8299
+ type: "transcript-final",
8300
+ id: segmentId(),
8301
+ text: segmentBuffer
8302
+ });
8303
+ fullText += fullText === "" ? segmentBuffer : ` ${segmentBuffer}`;
8304
+ segmentBuffer = "";
8305
+ segmentCounter++;
8306
+ };
8307
+ const finish = () => {
8308
+ if (finished) return;
8309
+ completeSegment();
8310
+ finished = true;
8311
+ controller.enqueue({
8312
+ type: "finish",
8313
+ text: fullText,
8314
+ segments: [],
8315
+ language,
8316
+ durationInSeconds: void 0,
8317
+ ...usageMetadata != null ? { providerMetadata: { google: { usageMetadata } } } : {}
8318
+ });
8319
+ controller.close();
8320
+ cleanup(1e3);
8321
+ };
8322
+ const sendAudio = async (socket) => {
8323
+ audioReader = audio.getReader();
8324
+ try {
8325
+ while (true) {
8326
+ const { done, value } = await audioReader.read();
8327
+ if (done || finished) break;
8328
+ socket.send(
8329
+ JSON.stringify({
8330
+ realtimeInput: {
8331
+ audio: {
8332
+ data: convertToBase644(value),
8333
+ mimeType: `audio/pcm;rate=${inputAudioRate}`
8334
+ }
8335
+ }
8336
+ })
8337
+ );
8338
+ await waitForWebSocketBufferDrain(socket);
8339
+ }
8340
+ } finally {
8341
+ audioReader.releaseLock();
8342
+ audioReader = void 0;
8343
+ }
8344
+ if (!finished) {
8345
+ socket.send(
8346
+ JSON.stringify({ realtimeInput: { audioStreamEnd: true } })
8347
+ );
8348
+ audioEnded = true;
8349
+ schedulePendingFinish();
8350
+ }
8351
+ };
8352
+ connection = connectToWebSocket({
8353
+ url,
8354
+ headers,
8355
+ webSocket,
8356
+ abortSignal,
8357
+ onAbort: finishWithError,
8358
+ onProcessingError: finishWithError,
8359
+ onOpen: (socket) => {
8360
+ controller.enqueue({ type: "stream-start", warnings });
8361
+ socket.send(JSON.stringify({ setup }));
8362
+ void setupComplete.then(() => finished ? void 0 : sendAudio(socket)).catch(finishWithError);
8363
+ },
8364
+ onMessageText: async (text) => {
8365
+ var _a, _b;
8366
+ if (finished) return;
8367
+ const parsed = await safeParseJSON2({ text });
8368
+ if (!parsed.success) return;
8369
+ const message = parsed.value;
8370
+ if (includeRawChunks) {
8371
+ controller.enqueue({ type: "raw", rawValue: message });
8372
+ }
8373
+ if (message.setupComplete != null) {
8374
+ resolveSetupComplete();
8375
+ }
8376
+ if (message.usageMetadata != null) {
8377
+ usageMetadata = message.usageMetadata;
8378
+ }
8379
+ if (message.error != null) {
8380
+ finishWithError(
8381
+ new Error((_a = message.error.message) != null ? _a : "Google Live API error")
8382
+ );
8383
+ return;
8384
+ }
8385
+ const serverContent = message.serverContent;
8386
+ const interim = serverContent == null ? void 0 : serverContent.interimInputTranscription;
8387
+ if (interim == null ? void 0 : interim.text) {
8388
+ schedulePendingFinish();
8389
+ latestInterim = interim.text;
8390
+ controller.enqueue({
8391
+ type: "transcript-partial",
8392
+ id: segmentId(),
8393
+ text: interim.text
8394
+ });
8395
+ }
8396
+ const transcription = (_b = serverContent == null ? void 0 : serverContent.inputTranscription) != null ? _b : message.inputTranscription;
8397
+ if (transcription != null) {
8398
+ if (transcription.languageCode != null) {
8399
+ language = transcription.languageCode;
8400
+ }
8401
+ if (transcription.text) {
8402
+ schedulePendingFinish();
8403
+ latestInterim = "";
8404
+ segmentBuffer += transcription.text;
8405
+ controller.enqueue({
8406
+ type: "transcript-delta",
8407
+ id: segmentId(),
8408
+ delta: transcription.text
8409
+ });
8410
+ }
8411
+ if (transcription.finished === true) {
8412
+ completeSegment();
8413
+ }
8414
+ }
8415
+ if (serverContent == null ? void 0 : serverContent.turnComplete) {
8416
+ completeSegment();
8417
+ }
8418
+ const interactionStatus = serverContent == null ? void 0 : serverContent.interactionStatus;
8419
+ if (audioEnded && (interactionStatus === "IDLE" || interactionStatus === "REQUIRES_ACTION" || (serverContent == null ? void 0 : serverContent.turnComplete) === true && interactionStatus == null)) {
8420
+ finish();
8421
+ }
8422
+ },
8423
+ onSocketError: () => {
8424
+ finishWithError(new Error("Google Live transcription error"));
8425
+ },
8426
+ onClose: ({ code, reason }) => {
8427
+ if (finished) return;
8428
+ if (audioEnded) {
8429
+ finish();
8430
+ return;
8431
+ }
8432
+ finishWithError(
8433
+ new Error(
8434
+ `Google Live transcription WebSocket closed unexpectedly before finishing (code ${code != null ? code : "unknown"}${reason ? `, reason: ${reason}` : ""}).`
8435
+ )
8436
+ );
8437
+ }
8438
+ });
8439
+ },
8440
+ cancel: () => {
8441
+ if (finished) return;
8442
+ finished = true;
8443
+ cleanup();
8444
+ }
8445
+ });
8446
+ }
8447
+ function buildAudioTranscriptionConfig(options) {
8448
+ if (options == null) return void 0;
8449
+ const config = {};
8450
+ if (options.languageCodes != null) {
8451
+ config.languageCodes = options.languageCodes;
8452
+ }
8453
+ if (options.customVocabulary != null) {
8454
+ config.customVocabulary = options.customVocabulary;
8455
+ }
8456
+ if (options.wordTimestamp != null) {
8457
+ config.wordTimestamp = options.wordTimestamp;
8458
+ }
8459
+ if (options.diarization != null) {
8460
+ config.diarization = options.diarization;
8461
+ }
8462
+ if (options.mode != null) {
8463
+ config.mode = options.mode;
8464
+ }
8465
+ return Object.keys(config).length > 0 ? config : void 0;
8466
+ }
8467
+ function buildTranscriptionConfig(options) {
8468
+ var _a;
8469
+ if (options == null) return void 0;
8470
+ const config = {};
8471
+ if (options.languageCodes != null) {
8472
+ config.language_codes = options.languageCodes;
8473
+ }
8474
+ if (options.customVocabulary != null) {
8475
+ config.custom_vocabulary = options.customVocabulary;
8476
+ }
8477
+ if (options.mode != null || options.diarization === true || options.wordTimestamp === true) {
8478
+ config.mode = {
8479
+ type: ((_a = options.mode) != null ? _a : "VERBATIM").toLowerCase(),
8480
+ ...options.diarization === true ? { diarization_mode: "speaker" } : {},
8481
+ ...options.wordTimestamp === true ? { timestamp_granularities: ["word"] } : {}
8482
+ };
8483
+ }
8484
+ return Object.keys(config).length > 0 ? config : void 0;
8485
+ }
8486
+ function parseOffsetSeconds(offset) {
8487
+ if (offset == null) return void 0;
8488
+ const parsed = Number.parseFloat(offset);
8489
+ return Number.isFinite(parsed) ? parsed : void 0;
8490
+ }
8491
+ function validateLiveInputAudioFormat(inputAudioFormat) {
8492
+ if (inputAudioFormat.type !== "audio/pcm" || inputAudioFormat.rate != null && inputAudioFormat.rate !== 16e3) {
8493
+ throw new InvalidArgumentError2({
8494
+ argument: "inputAudioFormat",
8495
+ message: "The Gemini Live transcription API only supports 16kHz 16-bit PCM input audio."
8496
+ });
8497
+ }
8498
+ }
8499
+ var googleInteractionsWordAnnotationSchema = z23.object({
8500
+ type: z23.string().nullish(),
8501
+ text: z23.string().nullish(),
8502
+ speaker: z23.string().nullish(),
8503
+ start_offset: z23.string().nullish(),
8504
+ end_offset: z23.string().nullish()
8505
+ });
8506
+ var googleInteractionsTranscriptionResponseSchema = z23.object({
8507
+ status: z23.string().nullish(),
8508
+ steps: z23.array(
8509
+ z23.object({
8510
+ type: z23.string().nullish(),
8511
+ content: z23.array(
8512
+ z23.object({
8513
+ type: z23.string().nullish(),
8514
+ text: z23.string().nullish(),
8515
+ annotations: z23.array(googleInteractionsWordAnnotationSchema).nullish()
8516
+ })
8517
+ ).nullish()
8518
+ })
8519
+ ).nullish(),
8520
+ usage: z23.record(z23.string(), z23.unknown()).nullish()
8521
+ });
8522
+
8523
+ // src/speech-translation/google-speech-translation-model.ts
8524
+ import {
8525
+ InvalidArgumentError as InvalidArgumentError3
8526
+ } from "@ai-sdk/provider";
8527
+ import {
8528
+ connectToWebSocket as connectToWebSocket2,
8529
+ combineHeaders as combineHeaders10,
8530
+ convertBase64ToUint8Array as convertBase64ToUint8Array2,
8531
+ convertToBase64 as convertToBase645,
8532
+ parseProviderOptions as parseProviderOptions9,
8533
+ safeParseJSON as safeParseJSON3,
8534
+ serializeModelOptions as serializeModelOptions7,
8535
+ WORKFLOW_DESERIALIZE as WORKFLOW_DESERIALIZE8,
8536
+ WORKFLOW_SERIALIZE as WORKFLOW_SERIALIZE8,
8537
+ waitForWebSocketBufferDrain as waitForWebSocketBufferDrain2
8032
8538
  } from "@ai-sdk/provider-utils";
8033
8539
 
8034
8540
  // src/speech-translation/google-speech-translation-model-options.ts
@@ -8036,26 +8542,26 @@ import {
8036
8542
  lazySchema as lazySchema20,
8037
8543
  zodSchema as zodSchema20
8038
8544
  } from "@ai-sdk/provider-utils";
8039
- import { z as z22 } from "zod/v4";
8545
+ import { z as z24 } from "zod/v4";
8040
8546
  var googleSpeechTranslationModelOptions = lazySchema20(
8041
8547
  () => zodSchema20(
8042
- z22.object({
8548
+ z24.object({
8043
8549
  /**
8044
8550
  * Whether input audio already in the target language should be echoed
8045
8551
  * instead of producing silence.
8046
8552
  */
8047
- echoTargetLanguage: z22.boolean().optional()
8553
+ echoTargetLanguage: z24.boolean().optional()
8048
8554
  })
8049
8555
  )
8050
8556
  );
8051
8557
 
8052
8558
  // src/speech-translation/google-speech-translation-model.ts
8053
- var liveWebSocketPath = "google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent";
8054
- var defaultFinishGraceMs = 1e3;
8559
+ var liveWebSocketPath2 = "google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent";
8560
+ var defaultFinishGraceMs2 = 1e3;
8055
8561
  var googleLiveOutputAudioRate = 24e3;
8056
8562
  var pcm16SilenceAmplitudeThreshold = 128;
8057
- function getLiveWebSocketURL(baseURL, apiKey) {
8058
- const url = getRealtimeWebSocketURL(baseURL, liveWebSocketPath);
8563
+ function getLiveWebSocketURL2(baseURL, apiKey) {
8564
+ const url = getRealtimeWebSocketURL(baseURL, liveWebSocketPath2);
8059
8565
  url.searchParams.set("key", apiKey);
8060
8566
  return url;
8061
8567
  }
@@ -8065,13 +8571,13 @@ var GoogleSpeechTranslationModel = class _GoogleSpeechTranslationModel {
8065
8571
  this.modelId = modelId;
8066
8572
  this.config = config;
8067
8573
  }
8068
- static [WORKFLOW_SERIALIZE7](model) {
8069
- return serializeModelOptions6({
8574
+ static [WORKFLOW_SERIALIZE8](model) {
8575
+ return serializeModelOptions7({
8070
8576
  modelId: model.modelId,
8071
8577
  config: model.config
8072
8578
  });
8073
8579
  }
8074
- static [WORKFLOW_DESERIALIZE7](options) {
8580
+ static [WORKFLOW_DESERIALIZE8](options) {
8075
8581
  return new _GoogleSpeechTranslationModel(options.modelId, options.config);
8076
8582
  }
8077
8583
  get provider() {
@@ -8080,13 +8586,13 @@ var GoogleSpeechTranslationModel = class _GoogleSpeechTranslationModel {
8080
8586
  async doStream(options) {
8081
8587
  var _a, _b, _c, _d, _e, _f;
8082
8588
  if (options.targetLanguage == null) {
8083
- throw new InvalidArgumentError2({
8589
+ throw new InvalidArgumentError3({
8084
8590
  argument: "targetLanguage",
8085
8591
  message: `targetLanguage is required for translation model '${this.modelId}'.`
8086
8592
  });
8087
8593
  }
8088
8594
  const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
8089
- const googleOptions = await parseProviderOptions8({
8595
+ const googleOptions = await parseProviderOptions9({
8090
8596
  provider: "google",
8091
8597
  providerOptions: options.providerOptions,
8092
8598
  schema: googleSpeechTranslationModelOptions
@@ -8107,7 +8613,7 @@ var GoogleSpeechTranslationModel = class _GoogleSpeechTranslationModel {
8107
8613
  details: "The Gemini Live API always outputs 24kHz 16-bit PCM audio and does not accept an output audio format."
8108
8614
  });
8109
8615
  }
8110
- const headers = combineHeaders9(this.config.headers(), options.headers);
8616
+ const headers = combineHeaders10(this.config.headers(), options.headers);
8111
8617
  let apiKey;
8112
8618
  for (const [key, value] of Object.entries(headers)) {
8113
8619
  if (key.toLowerCase() === "x-goog-api-key" && value != null) {
@@ -8137,11 +8643,11 @@ var GoogleSpeechTranslationModel = class _GoogleSpeechTranslationModel {
8137
8643
  },
8138
8644
  stream: createGoogleLiveSpeechTranslationStream({
8139
8645
  webSocket: this.config.webSocket,
8140
- url: getLiveWebSocketURL(this.config.baseURL, apiKey),
8646
+ url: getLiveWebSocketURL2(this.config.baseURL, apiKey),
8141
8647
  headers: webSocketHeaders,
8142
8648
  setup,
8143
8649
  inputAudioRate: (_d = options.inputAudioFormat.rate) != null ? _d : 16e3,
8144
- finishGraceMs: (_f = (_e = this.config._internal) == null ? void 0 : _e.finishGraceMs) != null ? _f : defaultFinishGraceMs,
8650
+ finishGraceMs: (_f = (_e = this.config._internal) == null ? void 0 : _e.finishGraceMs) != null ? _f : defaultFinishGraceMs2,
8145
8651
  warnings,
8146
8652
  audio: options.audio,
8147
8653
  abortSignal: options.abortSignal,
@@ -8170,8 +8676,8 @@ function createGoogleLiveSpeechTranslationStream({
8170
8676
  let audioReader;
8171
8677
  let connection;
8172
8678
  let resolveSetupComplete;
8173
- const setupComplete = new Promise((resolve7) => {
8174
- resolveSetupComplete = resolve7;
8679
+ const setupComplete = new Promise((resolve8) => {
8680
+ resolveSetupComplete = resolve8;
8175
8681
  });
8176
8682
  let turnCounter = 0;
8177
8683
  let sourceText = "";
@@ -8266,13 +8772,13 @@ function createGoogleLiveSpeechTranslationStream({
8266
8772
  JSON.stringify({
8267
8773
  realtimeInput: {
8268
8774
  audio: {
8269
- data: convertToBase644(value),
8775
+ data: convertToBase645(value),
8270
8776
  mimeType: `audio/pcm;rate=${inputAudioRate}`
8271
8777
  }
8272
8778
  }
8273
8779
  })
8274
8780
  );
8275
- await waitForWebSocketBufferDrain(socket);
8781
+ await waitForWebSocketBufferDrain2(socket);
8276
8782
  }
8277
8783
  } finally {
8278
8784
  audioReader.releaseLock();
@@ -8288,7 +8794,7 @@ function createGoogleLiveSpeechTranslationStream({
8288
8794
  }
8289
8795
  }
8290
8796
  };
8291
- connection = connectToWebSocket({
8797
+ connection = connectToWebSocket2({
8292
8798
  url,
8293
8799
  headers,
8294
8800
  webSocket,
@@ -8303,7 +8809,7 @@ function createGoogleLiveSpeechTranslationStream({
8303
8809
  onMessageText: async (text) => {
8304
8810
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
8305
8811
  if (finished) return;
8306
- const parsed = await safeParseJSON2({ text });
8812
+ const parsed = await safeParseJSON3({ text });
8307
8813
  if (!parsed.success) return;
8308
8814
  const message = parsed.value;
8309
8815
  if (includeRawChunks) {
@@ -8460,7 +8966,7 @@ function buildGoogleLiveSpeechTranslationSetup({
8460
8966
  }
8461
8967
  function validateGoogleSpeechTranslationInputAudioFormat(inputAudioFormat) {
8462
8968
  if (inputAudioFormat.type !== "audio/pcm" || inputAudioFormat.rate != null && inputAudioFormat.rate !== 16e3) {
8463
- throw new InvalidArgumentError2({
8969
+ throw new InvalidArgumentError3({
8464
8970
  argument: "inputAudioFormat",
8465
8971
  message: "The Gemini Live translation API only supports 16kHz 16-bit PCM input audio."
8466
8972
  });
@@ -8585,6 +9091,13 @@ function createGoogle(options = {}) {
8585
9091
  headers: getHeaders,
8586
9092
  fetch: options.fetch
8587
9093
  });
9094
+ const createTranscriptionModel = (modelId) => new GoogleTranscriptionModel(modelId, {
9095
+ provider: `${providerName}.transcription`,
9096
+ baseURL,
9097
+ headers: getHeaders,
9098
+ fetch: options.fetch,
9099
+ webSocket: options.webSocket
9100
+ });
8588
9101
  const experimentalRealtimeFactory = Object.assign(
8589
9102
  (modelId) => createRealtimeModel(modelId),
8590
9103
  {
@@ -8639,6 +9152,8 @@ function createGoogle(options = {}) {
8639
9152
  provider.files = createFiles;
8640
9153
  provider.speech = createSpeechModel;
8641
9154
  provider.speechModel = createSpeechModel;
9155
+ provider.transcription = createTranscriptionModel;
9156
+ provider.transcriptionModel = createTranscriptionModel;
8642
9157
  provider.translation = createSpeechTranslationModel;
8643
9158
  provider.speechTranslationModel = createSpeechTranslationModel;
8644
9159
  provider.interactions = createInteractionsModel;
@@ -8650,6 +9165,7 @@ export {
8650
9165
  GoogleRealtimeModel as Experimental_GoogleRealtimeModel,
8651
9166
  GoogleSpeechTranslationModel as Experimental_GoogleSpeechTranslationModel,
8652
9167
  GoogleSpeechTranslationModel as Experimental_GoogleTranslationModel,
9168
+ GoogleTranscriptionModel,
8653
9169
  VERSION,
8654
9170
  createGoogle,
8655
9171
  createGoogle as createGoogleGenerativeAI,