@ai-sdk/google 3.0.71 → 3.0.72

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.72" : "0.0.0-test";
11
11
 
12
12
  // src/google-generative-ai-embedding-model.ts
13
13
  import {
@@ -3078,8 +3078,8 @@ var googleVideoModelOptionsSchema = lazySchema12(
3078
3078
 
3079
3079
  // src/interactions/google-interactions-language-model.ts
3080
3080
  import {
3081
- combineHeaders as combineHeaders5,
3082
- createEventSourceResponseHandler as createEventSourceResponseHandler2,
3081
+ combineHeaders as combineHeaders6,
3082
+ createEventSourceResponseHandler as createEventSourceResponseHandler3,
3083
3083
  createJsonResponseHandler as createJsonResponseHandler6,
3084
3084
  generateId as defaultGenerateId2,
3085
3085
  parseProviderOptions as parseProviderOptions5,
@@ -4703,8 +4703,45 @@ function parseGoogleInteractionsOutputs({
4703
4703
  import {
4704
4704
  createJsonResponseHandler as createJsonResponseHandler5,
4705
4705
  delay as delay2,
4706
- getFromApi as getFromApi2
4706
+ getFromApi as getFromApi2,
4707
+ isAbortError
4708
+ } from "@ai-sdk/provider-utils";
4709
+
4710
+ // src/interactions/cancel-google-interaction.ts
4711
+ import {
4712
+ combineHeaders as combineHeaders5,
4713
+ getRuntimeEnvironmentUserAgent,
4714
+ withUserAgentSuffix
4707
4715
  } from "@ai-sdk/provider-utils";
4716
+ var getOriginalFetch = () => globalThis.fetch;
4717
+ async function cancelGoogleInteraction({
4718
+ baseURL,
4719
+ interactionId,
4720
+ headers,
4721
+ fetch = getOriginalFetch()
4722
+ }) {
4723
+ if (interactionId == null || interactionId.length === 0) {
4724
+ return;
4725
+ }
4726
+ const url = `${baseURL}/interactions/${encodeURIComponent(interactionId)}/cancel`;
4727
+ try {
4728
+ const response = await fetch(url, {
4729
+ method: "POST",
4730
+ headers: withUserAgentSuffix(
4731
+ combineHeaders5({ "Content-Type": "application/json" }, headers),
4732
+ getRuntimeEnvironmentUserAgent()
4733
+ ),
4734
+ body: "{}"
4735
+ });
4736
+ try {
4737
+ await response.text();
4738
+ } catch (e) {
4739
+ }
4740
+ } catch (e) {
4741
+ }
4742
+ }
4743
+
4744
+ // src/interactions/poll-google-interactions.ts
4708
4745
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "incomplete"]);
4709
4746
  function isTerminalStatus(status) {
4710
4747
  return status != null && TERMINAL_STATUSES.has(status);
@@ -4730,34 +4767,43 @@ async function pollGoogleInteractionUntilTerminal({
4730
4767
  const startedAt = Date.now();
4731
4768
  let nextDelayMs = initialDelayMs;
4732
4769
  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
- );
4770
+ const cancelOnServer = () => cancelGoogleInteraction({ baseURL, interactionId, headers, fetch });
4771
+ try {
4772
+ while (true) {
4773
+ if (abortSignal == null ? void 0 : abortSignal.aborted) {
4774
+ await cancelOnServer();
4775
+ throw new DOMException("Polling was aborted", "AbortError");
4776
+ }
4777
+ if (Date.now() - startedAt > timeoutMs) {
4778
+ throw new Error(
4779
+ `google.interactions: timed out polling interaction ${interactionId} after ${timeoutMs}ms.`
4780
+ );
4781
+ }
4782
+ await delay2(nextDelayMs, { abortSignal });
4783
+ const {
4784
+ value: response,
4785
+ rawValue: rawResponse,
4786
+ responseHeaders
4787
+ } = await getFromApi2({
4788
+ url,
4789
+ headers,
4790
+ failedResponseHandler: googleFailedResponseHandler,
4791
+ successfulResponseHandler: createJsonResponseHandler5(
4792
+ googleInteractionsResponseSchema
4793
+ ),
4794
+ abortSignal,
4795
+ fetch
4796
+ });
4797
+ if (isTerminalStatus(response.status)) {
4798
+ return { response, rawResponse, responseHeaders };
4799
+ }
4800
+ nextDelayMs = Math.min(nextDelayMs * 2, maxDelayMs);
4741
4801
  }
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 };
4802
+ } catch (error) {
4803
+ if (isAbortError(error)) {
4804
+ await cancelOnServer();
4759
4805
  }
4760
- nextDelayMs = Math.min(nextDelayMs * 2, maxDelayMs);
4806
+ throw error;
4761
4807
  }
4762
4808
  }
4763
4809
 
@@ -4909,6 +4955,174 @@ function prepareGoogleInteractionsTools({
4909
4955
  };
4910
4956
  }
4911
4957
 
4958
+ // src/interactions/stream-google-interactions.ts
4959
+ import {
4960
+ createEventSourceResponseHandler as createEventSourceResponseHandler2,
4961
+ delay as delay3,
4962
+ getFromApi as getFromApi3,
4963
+ isAbortError as isAbortError2
4964
+ } from "@ai-sdk/provider-utils";
4965
+ var DEFAULT_MAX_RETRIES = 3;
4966
+ var DEFAULT_RETRY_DELAY_MS = 500;
4967
+ function streamGoogleInteractionEvents({
4968
+ baseURL,
4969
+ interactionId,
4970
+ headers,
4971
+ fetch,
4972
+ abortSignal,
4973
+ maxRetries = DEFAULT_MAX_RETRIES,
4974
+ retryDelayMs = DEFAULT_RETRY_DELAY_MS
4975
+ }) {
4976
+ if (interactionId.length === 0) {
4977
+ throw new Error(
4978
+ "google.interactions: cannot stream a background interaction without an id."
4979
+ );
4980
+ }
4981
+ const eventSourceHeaders = {
4982
+ ...headers,
4983
+ accept: "text/event-stream"
4984
+ };
4985
+ let lastEventId;
4986
+ let complete = false;
4987
+ let attempt = 0;
4988
+ let receivedAnyEventThisAttempt = false;
4989
+ let currentReader;
4990
+ const internalAbort = new AbortController();
4991
+ const upstreamAbortHandler = () => internalAbort.abort();
4992
+ if (abortSignal != null) {
4993
+ if (abortSignal.aborted) {
4994
+ internalAbort.abort();
4995
+ } else {
4996
+ abortSignal.addEventListener("abort", upstreamAbortHandler, {
4997
+ once: true
4998
+ });
4999
+ }
5000
+ }
5001
+ const effectiveSignal = internalAbort.signal;
5002
+ function buildUrl() {
5003
+ const base = `${baseURL}/interactions/${encodeURIComponent(interactionId)}`;
5004
+ const params = new URLSearchParams({ stream: "true" });
5005
+ if (lastEventId != null) {
5006
+ params.set("last_event_id", lastEventId);
5007
+ }
5008
+ return `${base}?${params.toString()}`;
5009
+ }
5010
+ async function openReader() {
5011
+ const { value: stream } = await getFromApi3({
5012
+ url: buildUrl(),
5013
+ headers: eventSourceHeaders,
5014
+ failedResponseHandler: googleFailedResponseHandler,
5015
+ successfulResponseHandler: createEventSourceResponseHandler2(
5016
+ googleInteractionsEventSchema
5017
+ ),
5018
+ abortSignal: effectiveSignal,
5019
+ fetch
5020
+ });
5021
+ return stream.getReader();
5022
+ }
5023
+ return new ReadableStream({
5024
+ async start(controller) {
5025
+ try {
5026
+ while (!complete && !effectiveSignal.aborted) {
5027
+ if (currentReader == null) {
5028
+ try {
5029
+ currentReader = await openReader();
5030
+ receivedAnyEventThisAttempt = false;
5031
+ } catch (error) {
5032
+ if (isAbortError2(error) || effectiveSignal.aborted) {
5033
+ controller.error(error);
5034
+ return;
5035
+ }
5036
+ attempt++;
5037
+ if (attempt >= maxRetries) {
5038
+ controller.error(error);
5039
+ return;
5040
+ }
5041
+ await delay3(retryDelayMs * attempt, {
5042
+ abortSignal: effectiveSignal
5043
+ });
5044
+ continue;
5045
+ }
5046
+ }
5047
+ try {
5048
+ const { done, value } = await currentReader.read();
5049
+ if (done) {
5050
+ currentReader = void 0;
5051
+ if (complete) break;
5052
+ if (!receivedAnyEventThisAttempt) {
5053
+ attempt++;
5054
+ if (attempt >= maxRetries) {
5055
+ controller.error(
5056
+ new Error(
5057
+ "google.interactions: SSE stream closed without producing any events."
5058
+ )
5059
+ );
5060
+ return;
5061
+ }
5062
+ await delay3(retryDelayMs * attempt, {
5063
+ abortSignal: effectiveSignal
5064
+ });
5065
+ } else {
5066
+ attempt = 0;
5067
+ }
5068
+ continue;
5069
+ }
5070
+ receivedAnyEventThisAttempt = true;
5071
+ if (value.success) {
5072
+ const ev = value.value;
5073
+ if (typeof ev.event_id === "string" && ev.event_id.length > 0) {
5074
+ lastEventId = ev.event_id;
5075
+ }
5076
+ if (ev.event_type === "interaction.complete" || ev.event_type === "error") {
5077
+ complete = true;
5078
+ }
5079
+ }
5080
+ controller.enqueue(value);
5081
+ } catch (error) {
5082
+ if (isAbortError2(error) || effectiveSignal.aborted) {
5083
+ controller.error(error);
5084
+ return;
5085
+ }
5086
+ currentReader = void 0;
5087
+ attempt++;
5088
+ if (attempt >= maxRetries) {
5089
+ controller.error(error);
5090
+ return;
5091
+ }
5092
+ await delay3(retryDelayMs * attempt, {
5093
+ abortSignal: effectiveSignal
5094
+ });
5095
+ }
5096
+ }
5097
+ controller.close();
5098
+ } catch (error) {
5099
+ controller.error(error);
5100
+ } finally {
5101
+ if (abortSignal != null) {
5102
+ abortSignal.removeEventListener("abort", upstreamAbortHandler);
5103
+ }
5104
+ currentReader == null ? void 0 : currentReader.cancel().catch(() => {
5105
+ });
5106
+ currentReader = void 0;
5107
+ if (effectiveSignal.aborted && !complete) {
5108
+ await cancelGoogleInteraction({
5109
+ baseURL,
5110
+ interactionId,
5111
+ headers,
5112
+ fetch
5113
+ });
5114
+ }
5115
+ }
5116
+ },
5117
+ cancel() {
5118
+ internalAbort.abort();
5119
+ currentReader == null ? void 0 : currentReader.cancel().catch(() => {
5120
+ });
5121
+ currentReader = void 0;
5122
+ }
5123
+ });
5124
+ }
5125
+
4912
5126
  // src/interactions/synthesize-google-interactions-agent-stream.ts
4913
5127
  function synthesizeGoogleInteractionsAgentStream({
4914
5128
  response,
@@ -5222,7 +5436,7 @@ var GoogleInteractionsLanguageModel = class {
5222
5436
  var _a, _b, _c, _d, _e, _f;
5223
5437
  const { args, warnings, isAgent, pollingTimeoutMs } = await this.getArgs(options);
5224
5438
  const url = `${this.config.baseURL}/interactions`;
5225
- const mergedHeaders = combineHeaders5(
5439
+ const mergedHeaders = combineHeaders6(
5226
5440
  this.config.headers ? await resolve5(this.config.headers) : void 0,
5227
5441
  options.headers
5228
5442
  );
@@ -5302,12 +5516,12 @@ var GoogleInteractionsLanguageModel = class {
5302
5516
  var _a;
5303
5517
  const { args, warnings, isAgent, pollingTimeoutMs } = await this.getArgs(options);
5304
5518
  const url = `${this.config.baseURL}/interactions`;
5305
- const mergedHeaders = combineHeaders5(
5519
+ const mergedHeaders = combineHeaders6(
5306
5520
  this.config.headers ? await resolve5(this.config.headers) : void 0,
5307
5521
  options.headers
5308
5522
  );
5309
5523
  if (isAgent) {
5310
- return this.doStreamAgent({
5524
+ return this.doStreamBackground({
5311
5525
  args,
5312
5526
  warnings,
5313
5527
  url,
@@ -5322,7 +5536,7 @@ var GoogleInteractionsLanguageModel = class {
5322
5536
  headers: mergedHeaders,
5323
5537
  body,
5324
5538
  failedResponseHandler: googleFailedResponseHandler,
5325
- successfulResponseHandler: createEventSourceResponseHandler2(
5539
+ successfulResponseHandler: createEventSourceResponseHandler3(
5326
5540
  googleInteractionsEventSchema
5327
5541
  ),
5328
5542
  abortSignal: options.abortSignal,
@@ -5342,26 +5556,24 @@ var GoogleInteractionsLanguageModel = class {
5342
5556
  };
5343
5557
  }
5344
5558
  /*
5345
- * Drive the streaming surface for agent calls. Agent calls require
5559
+ * Drive the streaming surface for agent calls. Agents require
5346
5560
  * `background: true`, which is incompatible with `stream: true` on POST.
5347
5561
  *
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.
5562
+ * Approach:
5563
+ * 1. POST `/interactions` with `background: true`. The response includes
5564
+ * the interaction id and an initial (usually non-terminal) status.
5565
+ * 2. If the POST status is already terminal (rare), synthesize a stream
5566
+ * from the polled outputs and we're done.
5567
+ * 3. Otherwise open `GET /interactions/{id}?stream=true` and pipe the
5568
+ * SSE events through `buildGoogleInteractionsStreamTransform` so the
5569
+ * consumer receives text deltas / thinking summaries / tool events as
5570
+ * they happen instead of all at once at the end.
5356
5571
  *
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.
5572
+ * The SSE connection can drop while the agent idles between events
5573
+ * (`UND_ERR_BODY_TIMEOUT`); `streamGoogleInteractionEvents` handles the
5574
+ * reconnect-with-`last_event_id` loop transparently.
5363
5575
  */
5364
- async doStreamAgent({
5576
+ async doStreamBackground({
5365
5577
  args,
5366
5578
  warnings,
5367
5579
  url,
@@ -5381,34 +5593,44 @@ var GoogleInteractionsLanguageModel = class {
5381
5593
  abortSignal: options.abortSignal,
5382
5594
  fetch: this.config.fetch
5383
5595
  });
5384
- let { responseHeaders: postHeaders, value: postResponse } = postResult;
5596
+ const { responseHeaders: postHeaders, value: postResponse } = postResult;
5385
5597
  const interactionId = postResponse.id;
5386
5598
  if (interactionId == null || interactionId.length === 0) {
5387
5599
  throw new Error(
5388
- "google.interactions: agent POST response did not include an interaction id; cannot poll for the agent result."
5600
+ "google.interactions: background POST response did not include an interaction id; cannot stream the result."
5389
5601
  );
5390
5602
  }
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
5603
+ const headerServiceTier = postHeaders == null ? void 0 : postHeaders["x-gemini-service-tier"];
5604
+ if (isTerminalStatus(postResponse.status)) {
5605
+ const synthesized = synthesizeGoogleInteractionsAgentStream({
5606
+ response: postResponse,
5607
+ warnings,
5608
+ generateId: (_a = this.config.generateId) != null ? _a : defaultGenerateId2,
5609
+ includeRawChunks: options.includeRawChunks,
5610
+ headerServiceTier
5399
5611
  });
5400
- postResponse = polled.response;
5401
- postHeaders = (_a = polled.responseHeaders) != null ? _a : postHeaders;
5612
+ return {
5613
+ stream: synthesized,
5614
+ request: { body: args },
5615
+ response: { headers: postHeaders }
5616
+ };
5402
5617
  }
5403
- const stream = synthesizeGoogleInteractionsAgentStream({
5404
- response: postResponse,
5618
+ void pollingTimeoutMs;
5619
+ const events = streamGoogleInteractionEvents({
5620
+ baseURL: this.config.baseURL,
5621
+ interactionId,
5622
+ headers: mergedHeaders,
5623
+ fetch: this.config.fetch,
5624
+ abortSignal: options.abortSignal
5625
+ });
5626
+ const transform = buildGoogleInteractionsStreamTransform({
5405
5627
  warnings,
5406
5628
  generateId: (_b = this.config.generateId) != null ? _b : defaultGenerateId2,
5407
5629
  includeRawChunks: options.includeRawChunks,
5408
- headerServiceTier: postHeaders == null ? void 0 : postHeaders["x-gemini-service-tier"]
5630
+ serviceTier: headerServiceTier
5409
5631
  });
5410
5632
  return {
5411
- stream,
5633
+ stream: events.pipeThrough(transform),
5412
5634
  request: { body: args },
5413
5635
  response: { headers: postHeaders }
5414
5636
  };
@@ -5428,7 +5650,7 @@ function createGoogleGenerativeAI(options = {}) {
5428
5650
  var _a, _b;
5429
5651
  const baseURL = (_a = withoutTrailingSlash(options.baseURL)) != null ? _a : "https://generativelanguage.googleapis.com/v1beta";
5430
5652
  const providerName = (_b = options.name) != null ? _b : "google.generative-ai";
5431
- const getHeaders = () => withUserAgentSuffix(
5653
+ const getHeaders = () => withUserAgentSuffix2(
5432
5654
  {
5433
5655
  "x-goog-api-key": loadApiKey({
5434
5656
  apiKey: options.apiKey,