@ai-sdk/google 3.0.71 → 3.0.73

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.mjs CHANGED
@@ -3,11 +3,11 @@ import {
3
3
  generateId as generateId2,
4
4
  loadApiKey,
5
5
  withoutTrailingSlash,
6
- withUserAgentSuffix
6
+ withUserAgentSuffix as withUserAgentSuffix2
7
7
  } from "@ai-sdk/provider-utils";
8
8
 
9
9
  // src/version.ts
10
- var VERSION = true ? "3.0.71" : "0.0.0-test";
10
+ var VERSION = true ? "3.0.73" : "0.0.0-test";
11
11
 
12
12
  // src/google-generative-ai-embedding-model.ts
13
13
  import {
@@ -60,6 +60,12 @@ var googleEmbeddingContentPartSchema = z2.union([
60
60
  mimeType: z2.string(),
61
61
  data: z2.string()
62
62
  })
63
+ }),
64
+ z2.object({
65
+ fileData: z2.object({
66
+ fileUri: z2.string(),
67
+ mimeType: z2.string()
68
+ })
63
69
  })
64
70
  ]);
65
71
  var googleEmbeddingModelOptions = lazySchema2(
@@ -3078,8 +3084,8 @@ var googleVideoModelOptionsSchema = lazySchema12(
3078
3084
 
3079
3085
  // src/interactions/google-interactions-language-model.ts
3080
3086
  import {
3081
- combineHeaders as combineHeaders5,
3082
- createEventSourceResponseHandler as createEventSourceResponseHandler2,
3087
+ combineHeaders as combineHeaders6,
3088
+ createEventSourceResponseHandler as createEventSourceResponseHandler3,
3083
3089
  createJsonResponseHandler as createJsonResponseHandler6,
3084
3090
  generateId as defaultGenerateId2,
3085
3091
  parseProviderOptions as parseProviderOptions5,
@@ -4703,8 +4709,45 @@ function parseGoogleInteractionsOutputs({
4703
4709
  import {
4704
4710
  createJsonResponseHandler as createJsonResponseHandler5,
4705
4711
  delay as delay2,
4706
- getFromApi as getFromApi2
4712
+ getFromApi as getFromApi2,
4713
+ isAbortError
4714
+ } from "@ai-sdk/provider-utils";
4715
+
4716
+ // src/interactions/cancel-google-interaction.ts
4717
+ import {
4718
+ combineHeaders as combineHeaders5,
4719
+ getRuntimeEnvironmentUserAgent,
4720
+ withUserAgentSuffix
4707
4721
  } from "@ai-sdk/provider-utils";
4722
+ var getOriginalFetch = () => globalThis.fetch;
4723
+ async function cancelGoogleInteraction({
4724
+ baseURL,
4725
+ interactionId,
4726
+ headers,
4727
+ fetch = getOriginalFetch()
4728
+ }) {
4729
+ if (interactionId == null || interactionId.length === 0) {
4730
+ return;
4731
+ }
4732
+ const url = `${baseURL}/interactions/${encodeURIComponent(interactionId)}/cancel`;
4733
+ try {
4734
+ const response = await fetch(url, {
4735
+ method: "POST",
4736
+ headers: withUserAgentSuffix(
4737
+ combineHeaders5({ "Content-Type": "application/json" }, headers),
4738
+ getRuntimeEnvironmentUserAgent()
4739
+ ),
4740
+ body: "{}"
4741
+ });
4742
+ try {
4743
+ await response.text();
4744
+ } catch (e) {
4745
+ }
4746
+ } catch (e) {
4747
+ }
4748
+ }
4749
+
4750
+ // src/interactions/poll-google-interactions.ts
4708
4751
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "incomplete"]);
4709
4752
  function isTerminalStatus(status) {
4710
4753
  return status != null && TERMINAL_STATUSES.has(status);
@@ -4730,34 +4773,43 @@ async function pollGoogleInteractionUntilTerminal({
4730
4773
  const startedAt = Date.now();
4731
4774
  let nextDelayMs = initialDelayMs;
4732
4775
  const url = `${baseURL}/interactions/${encodeURIComponent(interactionId)}`;
4733
- while (true) {
4734
- if (abortSignal == null ? void 0 : abortSignal.aborted) {
4735
- throw new DOMException("Polling was aborted", "AbortError");
4736
- }
4737
- if (Date.now() - startedAt > timeoutMs) {
4738
- throw new Error(
4739
- `google.interactions: timed out polling interaction ${interactionId} after ${timeoutMs}ms.`
4740
- );
4776
+ const cancelOnServer = () => cancelGoogleInteraction({ baseURL, interactionId, headers, fetch });
4777
+ try {
4778
+ while (true) {
4779
+ if (abortSignal == null ? void 0 : abortSignal.aborted) {
4780
+ await cancelOnServer();
4781
+ throw new DOMException("Polling was aborted", "AbortError");
4782
+ }
4783
+ if (Date.now() - startedAt > timeoutMs) {
4784
+ throw new Error(
4785
+ `google.interactions: timed out polling interaction ${interactionId} after ${timeoutMs}ms.`
4786
+ );
4787
+ }
4788
+ await delay2(nextDelayMs, { abortSignal });
4789
+ const {
4790
+ value: response,
4791
+ rawValue: rawResponse,
4792
+ responseHeaders
4793
+ } = await getFromApi2({
4794
+ url,
4795
+ headers,
4796
+ failedResponseHandler: googleFailedResponseHandler,
4797
+ successfulResponseHandler: createJsonResponseHandler5(
4798
+ googleInteractionsResponseSchema
4799
+ ),
4800
+ abortSignal,
4801
+ fetch
4802
+ });
4803
+ if (isTerminalStatus(response.status)) {
4804
+ return { response, rawResponse, responseHeaders };
4805
+ }
4806
+ nextDelayMs = Math.min(nextDelayMs * 2, maxDelayMs);
4741
4807
  }
4742
- await delay2(nextDelayMs, { abortSignal });
4743
- const {
4744
- value: response,
4745
- rawValue: rawResponse,
4746
- responseHeaders
4747
- } = await getFromApi2({
4748
- url,
4749
- headers,
4750
- failedResponseHandler: googleFailedResponseHandler,
4751
- successfulResponseHandler: createJsonResponseHandler5(
4752
- googleInteractionsResponseSchema
4753
- ),
4754
- abortSignal,
4755
- fetch
4756
- });
4757
- if (isTerminalStatus(response.status)) {
4758
- return { response, rawResponse, responseHeaders };
4808
+ } catch (error) {
4809
+ if (isAbortError(error)) {
4810
+ await cancelOnServer();
4759
4811
  }
4760
- nextDelayMs = Math.min(nextDelayMs * 2, maxDelayMs);
4812
+ throw error;
4761
4813
  }
4762
4814
  }
4763
4815
 
@@ -4909,6 +4961,174 @@ function prepareGoogleInteractionsTools({
4909
4961
  };
4910
4962
  }
4911
4963
 
4964
+ // src/interactions/stream-google-interactions.ts
4965
+ import {
4966
+ createEventSourceResponseHandler as createEventSourceResponseHandler2,
4967
+ delay as delay3,
4968
+ getFromApi as getFromApi3,
4969
+ isAbortError as isAbortError2
4970
+ } from "@ai-sdk/provider-utils";
4971
+ var DEFAULT_MAX_RETRIES = 3;
4972
+ var DEFAULT_RETRY_DELAY_MS = 500;
4973
+ function streamGoogleInteractionEvents({
4974
+ baseURL,
4975
+ interactionId,
4976
+ headers,
4977
+ fetch,
4978
+ abortSignal,
4979
+ maxRetries = DEFAULT_MAX_RETRIES,
4980
+ retryDelayMs = DEFAULT_RETRY_DELAY_MS
4981
+ }) {
4982
+ if (interactionId.length === 0) {
4983
+ throw new Error(
4984
+ "google.interactions: cannot stream a background interaction without an id."
4985
+ );
4986
+ }
4987
+ const eventSourceHeaders = {
4988
+ ...headers,
4989
+ accept: "text/event-stream"
4990
+ };
4991
+ let lastEventId;
4992
+ let complete = false;
4993
+ let attempt = 0;
4994
+ let receivedAnyEventThisAttempt = false;
4995
+ let currentReader;
4996
+ const internalAbort = new AbortController();
4997
+ const upstreamAbortHandler = () => internalAbort.abort();
4998
+ if (abortSignal != null) {
4999
+ if (abortSignal.aborted) {
5000
+ internalAbort.abort();
5001
+ } else {
5002
+ abortSignal.addEventListener("abort", upstreamAbortHandler, {
5003
+ once: true
5004
+ });
5005
+ }
5006
+ }
5007
+ const effectiveSignal = internalAbort.signal;
5008
+ function buildUrl() {
5009
+ const base = `${baseURL}/interactions/${encodeURIComponent(interactionId)}`;
5010
+ const params = new URLSearchParams({ stream: "true" });
5011
+ if (lastEventId != null) {
5012
+ params.set("last_event_id", lastEventId);
5013
+ }
5014
+ return `${base}?${params.toString()}`;
5015
+ }
5016
+ async function openReader() {
5017
+ const { value: stream } = await getFromApi3({
5018
+ url: buildUrl(),
5019
+ headers: eventSourceHeaders,
5020
+ failedResponseHandler: googleFailedResponseHandler,
5021
+ successfulResponseHandler: createEventSourceResponseHandler2(
5022
+ googleInteractionsEventSchema
5023
+ ),
5024
+ abortSignal: effectiveSignal,
5025
+ fetch
5026
+ });
5027
+ return stream.getReader();
5028
+ }
5029
+ return new ReadableStream({
5030
+ async start(controller) {
5031
+ try {
5032
+ while (!complete && !effectiveSignal.aborted) {
5033
+ if (currentReader == null) {
5034
+ try {
5035
+ currentReader = await openReader();
5036
+ receivedAnyEventThisAttempt = false;
5037
+ } catch (error) {
5038
+ if (isAbortError2(error) || effectiveSignal.aborted) {
5039
+ controller.error(error);
5040
+ return;
5041
+ }
5042
+ attempt++;
5043
+ if (attempt >= maxRetries) {
5044
+ controller.error(error);
5045
+ return;
5046
+ }
5047
+ await delay3(retryDelayMs * attempt, {
5048
+ abortSignal: effectiveSignal
5049
+ });
5050
+ continue;
5051
+ }
5052
+ }
5053
+ try {
5054
+ const { done, value } = await currentReader.read();
5055
+ if (done) {
5056
+ currentReader = void 0;
5057
+ if (complete) break;
5058
+ if (!receivedAnyEventThisAttempt) {
5059
+ attempt++;
5060
+ if (attempt >= maxRetries) {
5061
+ controller.error(
5062
+ new Error(
5063
+ "google.interactions: SSE stream closed without producing any events."
5064
+ )
5065
+ );
5066
+ return;
5067
+ }
5068
+ await delay3(retryDelayMs * attempt, {
5069
+ abortSignal: effectiveSignal
5070
+ });
5071
+ } else {
5072
+ attempt = 0;
5073
+ }
5074
+ continue;
5075
+ }
5076
+ receivedAnyEventThisAttempt = true;
5077
+ if (value.success) {
5078
+ const ev = value.value;
5079
+ if (typeof ev.event_id === "string" && ev.event_id.length > 0) {
5080
+ lastEventId = ev.event_id;
5081
+ }
5082
+ if (ev.event_type === "interaction.complete" || ev.event_type === "error") {
5083
+ complete = true;
5084
+ }
5085
+ }
5086
+ controller.enqueue(value);
5087
+ } catch (error) {
5088
+ if (isAbortError2(error) || effectiveSignal.aborted) {
5089
+ controller.error(error);
5090
+ return;
5091
+ }
5092
+ currentReader = void 0;
5093
+ attempt++;
5094
+ if (attempt >= maxRetries) {
5095
+ controller.error(error);
5096
+ return;
5097
+ }
5098
+ await delay3(retryDelayMs * attempt, {
5099
+ abortSignal: effectiveSignal
5100
+ });
5101
+ }
5102
+ }
5103
+ controller.close();
5104
+ } catch (error) {
5105
+ controller.error(error);
5106
+ } finally {
5107
+ if (abortSignal != null) {
5108
+ abortSignal.removeEventListener("abort", upstreamAbortHandler);
5109
+ }
5110
+ currentReader == null ? void 0 : currentReader.cancel().catch(() => {
5111
+ });
5112
+ currentReader = void 0;
5113
+ if (effectiveSignal.aborted && !complete) {
5114
+ await cancelGoogleInteraction({
5115
+ baseURL,
5116
+ interactionId,
5117
+ headers,
5118
+ fetch
5119
+ });
5120
+ }
5121
+ }
5122
+ },
5123
+ cancel() {
5124
+ internalAbort.abort();
5125
+ currentReader == null ? void 0 : currentReader.cancel().catch(() => {
5126
+ });
5127
+ currentReader = void 0;
5128
+ }
5129
+ });
5130
+ }
5131
+
4912
5132
  // src/interactions/synthesize-google-interactions-agent-stream.ts
4913
5133
  function synthesizeGoogleInteractionsAgentStream({
4914
5134
  response,
@@ -5222,7 +5442,7 @@ var GoogleInteractionsLanguageModel = class {
5222
5442
  var _a, _b, _c, _d, _e, _f;
5223
5443
  const { args, warnings, isAgent, pollingTimeoutMs } = await this.getArgs(options);
5224
5444
  const url = `${this.config.baseURL}/interactions`;
5225
- const mergedHeaders = combineHeaders5(
5445
+ const mergedHeaders = combineHeaders6(
5226
5446
  this.config.headers ? await resolve5(this.config.headers) : void 0,
5227
5447
  options.headers
5228
5448
  );
@@ -5302,12 +5522,12 @@ var GoogleInteractionsLanguageModel = class {
5302
5522
  var _a;
5303
5523
  const { args, warnings, isAgent, pollingTimeoutMs } = await this.getArgs(options);
5304
5524
  const url = `${this.config.baseURL}/interactions`;
5305
- const mergedHeaders = combineHeaders5(
5525
+ const mergedHeaders = combineHeaders6(
5306
5526
  this.config.headers ? await resolve5(this.config.headers) : void 0,
5307
5527
  options.headers
5308
5528
  );
5309
5529
  if (isAgent) {
5310
- return this.doStreamAgent({
5530
+ return this.doStreamBackground({
5311
5531
  args,
5312
5532
  warnings,
5313
5533
  url,
@@ -5322,7 +5542,7 @@ var GoogleInteractionsLanguageModel = class {
5322
5542
  headers: mergedHeaders,
5323
5543
  body,
5324
5544
  failedResponseHandler: googleFailedResponseHandler,
5325
- successfulResponseHandler: createEventSourceResponseHandler2(
5545
+ successfulResponseHandler: createEventSourceResponseHandler3(
5326
5546
  googleInteractionsEventSchema
5327
5547
  ),
5328
5548
  abortSignal: options.abortSignal,
@@ -5342,26 +5562,24 @@ var GoogleInteractionsLanguageModel = class {
5342
5562
  };
5343
5563
  }
5344
5564
  /*
5345
- * Drive the streaming surface for agent calls. Agent calls require
5565
+ * Drive the streaming surface for agent calls. Agents require
5346
5566
  * `background: true`, which is incompatible with `stream: true` on POST.
5347
5567
  *
5348
- * In principle the API also exposes `GET /interactions/{id}?stream=true`
5349
- * to replay events as the agent runs. In practice the connection is
5350
- * idle for long stretches while the agent thinks (deep-research can run
5351
- * for a minute or more between SSE events), and undici's default body
5352
- * timeout terminates the request mid-flight with `UND_ERR_BODY_TIMEOUT`.
5353
- * Tuning the timeout per-call would require the caller to thread an
5354
- * `undici.Agent` through `fetch`, which contradicts the AI SDK's
5355
- * pluggable-fetch contract.
5568
+ * Approach:
5569
+ * 1. POST `/interactions` with `background: true`. The response includes
5570
+ * the interaction id and an initial (usually non-terminal) status.
5571
+ * 2. If the POST status is already terminal (rare), synthesize a stream
5572
+ * from the polled outputs and we're done.
5573
+ * 3. Otherwise open `GET /interactions/{id}?stream=true` and pipe the
5574
+ * SSE events through `buildGoogleInteractionsStreamTransform` so the
5575
+ * consumer receives text deltas / thinking summaries / tool events as
5576
+ * they happen instead of all at once at the end.
5356
5577
  *
5357
- * We therefore drive `doStream` exactly like `doGenerate` for agents:
5358
- * POST with `background: true`, poll `GET /interactions/{id}` until
5359
- * terminal, then synthesize the stream from the final outputs. The
5360
- * user-facing surface stays identical -- text-start / text-delta /
5361
- * text-end / finish parts arrive in the same order as a true SSE
5362
- * response, just buffered until the agent completes.
5578
+ * The SSE connection can drop while the agent idles between events
5579
+ * (`UND_ERR_BODY_TIMEOUT`); `streamGoogleInteractionEvents` handles the
5580
+ * reconnect-with-`last_event_id` loop transparently.
5363
5581
  */
5364
- async doStreamAgent({
5582
+ async doStreamBackground({
5365
5583
  args,
5366
5584
  warnings,
5367
5585
  url,
@@ -5381,34 +5599,44 @@ var GoogleInteractionsLanguageModel = class {
5381
5599
  abortSignal: options.abortSignal,
5382
5600
  fetch: this.config.fetch
5383
5601
  });
5384
- let { responseHeaders: postHeaders, value: postResponse } = postResult;
5602
+ const { responseHeaders: postHeaders, value: postResponse } = postResult;
5385
5603
  const interactionId = postResponse.id;
5386
5604
  if (interactionId == null || interactionId.length === 0) {
5387
5605
  throw new Error(
5388
- "google.interactions: agent POST response did not include an interaction id; cannot poll for the agent result."
5606
+ "google.interactions: background POST response did not include an interaction id; cannot stream the result."
5389
5607
  );
5390
5608
  }
5391
- if (!isTerminalStatus(postResponse.status)) {
5392
- const polled = await pollGoogleInteractionUntilTerminal({
5393
- baseURL: this.config.baseURL,
5394
- interactionId,
5395
- headers: mergedHeaders,
5396
- fetch: this.config.fetch,
5397
- abortSignal: options.abortSignal,
5398
- timeoutMs: pollingTimeoutMs
5609
+ const headerServiceTier = postHeaders == null ? void 0 : postHeaders["x-gemini-service-tier"];
5610
+ if (isTerminalStatus(postResponse.status)) {
5611
+ const synthesized = synthesizeGoogleInteractionsAgentStream({
5612
+ response: postResponse,
5613
+ warnings,
5614
+ generateId: (_a = this.config.generateId) != null ? _a : defaultGenerateId2,
5615
+ includeRawChunks: options.includeRawChunks,
5616
+ headerServiceTier
5399
5617
  });
5400
- postResponse = polled.response;
5401
- postHeaders = (_a = polled.responseHeaders) != null ? _a : postHeaders;
5618
+ return {
5619
+ stream: synthesized,
5620
+ request: { body: args },
5621
+ response: { headers: postHeaders }
5622
+ };
5402
5623
  }
5403
- const stream = synthesizeGoogleInteractionsAgentStream({
5404
- response: postResponse,
5624
+ void pollingTimeoutMs;
5625
+ const events = streamGoogleInteractionEvents({
5626
+ baseURL: this.config.baseURL,
5627
+ interactionId,
5628
+ headers: mergedHeaders,
5629
+ fetch: this.config.fetch,
5630
+ abortSignal: options.abortSignal
5631
+ });
5632
+ const transform = buildGoogleInteractionsStreamTransform({
5405
5633
  warnings,
5406
5634
  generateId: (_b = this.config.generateId) != null ? _b : defaultGenerateId2,
5407
5635
  includeRawChunks: options.includeRawChunks,
5408
- headerServiceTier: postHeaders == null ? void 0 : postHeaders["x-gemini-service-tier"]
5636
+ serviceTier: headerServiceTier
5409
5637
  });
5410
5638
  return {
5411
- stream,
5639
+ stream: events.pipeThrough(transform),
5412
5640
  request: { body: args },
5413
5641
  response: { headers: postHeaders }
5414
5642
  };
@@ -5428,7 +5656,7 @@ function createGoogleGenerativeAI(options = {}) {
5428
5656
  var _a, _b;
5429
5657
  const baseURL = (_a = withoutTrailingSlash(options.baseURL)) != null ? _a : "https://generativelanguage.googleapis.com/v1beta";
5430
5658
  const providerName = (_b = options.name) != null ? _b : "google.generative-ai";
5431
- const getHeaders = () => withUserAgentSuffix(
5659
+ const getHeaders = () => withUserAgentSuffix2(
5432
5660
  {
5433
5661
  "x-goog-api-key": loadApiKey({
5434
5662
  apiKey: options.apiKey,