ai 7.0.118 → 7.0.120

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.js +83 -31
  4. package/dist/index.js.map +1 -1
  5. package/dist/internal/index.js +3 -1
  6. package/dist/internal/index.js.map +1 -1
  7. package/dist/test/index.d.ts +5 -1
  8. package/dist/test/index.js +4 -0
  9. package/dist/test/index.js.map +1 -1
  10. package/docs/02-foundations/02-providers-and-models.mdx +1 -0
  11. package/docs/02-getting-started/00-choosing-a-provider.mdx +4 -4
  12. package/docs/02-getting-started/02-nextjs-app-router.mdx +2 -2
  13. package/docs/02-getting-started/03-nextjs-pages-router.mdx +2 -2
  14. package/docs/02-getting-started/04-svelte.mdx +6 -6
  15. package/docs/02-getting-started/05-nuxt.mdx +6 -6
  16. package/docs/02-getting-started/06-nodejs.mdx +2 -2
  17. package/docs/02-getting-started/07-expo.mdx +2 -2
  18. package/docs/02-getting-started/08-tanstack-start.mdx +2 -2
  19. package/docs/03-agents/06-policy-tool-approvals.mdx +2 -2
  20. package/docs/03-agents/07-workflow-agent.mdx +10 -10
  21. package/docs/03-ai-sdk-core/20-prompt-engineering.mdx +1 -1
  22. package/docs/03-ai-sdk-core/26-reasoning.mdx +1 -1
  23. package/docs/03-ai-sdk-core/35-image-generation.mdx +38 -0
  24. package/docs/03-ai-sdk-core/36-transcription.mdx +1 -0
  25. package/docs/03-ai-sdk-core/45-provider-management.mdx +4 -4
  26. package/docs/03-ai-sdk-harnesses/02-harness-agent.mdx +51 -9
  27. package/docs/04-ai-sdk-ui/02-chatbot.mdx +1 -1
  28. package/docs/07-reference/01-ai-sdk-core/61-wrap-image-model.mdx +16 -1
  29. package/docs/07-reference/04-ai-sdk-workflow/01-workflow-agent.mdx +8 -8
  30. package/package.json +12 -12
  31. package/src/middleware/wrap-image-model.ts +13 -0
  32. package/src/telemetry/tracing-channel-publisher.ts +1 -0
  33. package/src/test/mock-image-model-v4.ts +8 -0
  34. package/src/ui/chat.ts +36 -7
  35. package/src/ui/process-ui-message-stream.ts +9 -10
  36. package/src/util/write-to-server-response.ts +41 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # ai
2
2
 
3
+ ## 7.0.120
4
+
5
+ ### Patch Changes
6
+
7
+ - b032d70: fix(ai): preserve tool metadata from tool output chunks
8
+ - e21b98b: fix(ai): continue active UI message parts when resuming after a disconnect
9
+ - Updated dependencies [e361d39]
10
+ - @ai-sdk/gateway@4.0.98
11
+
12
+ ## 7.0.119
13
+
14
+ ### Patch Changes
15
+
16
+ - 33e94ba: fix(ai): cancel response streams when clients disconnect
17
+ - 34d869e: fix(ai): prevent unhandled stream completion rejections in non-Node runtimes
18
+ - def4df8: fix(ai): store static tool input errors in the current input field
19
+ - 525efc5: feat(provider): advertise image model file and mask input support
20
+
21
+ Use confirmed model IDs for capability declarations so unrecognized model names
22
+ remain unknown. Include Together AI FLUX.2 Pro and Flex single-image editing, and
23
+ allow asynchronous capability lookups and middleware overrides to resolve to
24
+ unknown.
25
+
26
+ Advertise QuiverAI Arrow 2 and Arrow 2 Telos file-input support, and mark Together
27
+ AI Gemini image inputs unsupported by the current single-image request mapping.
28
+
29
+ - Updated dependencies [e3605f6]
30
+ - Updated dependencies [525efc5]
31
+ - @ai-sdk/provider-utils@5.0.50
32
+ - @ai-sdk/provider@4.0.19
33
+ - @ai-sdk/gateway@4.0.97
34
+
3
35
  ## 7.0.118
4
36
 
5
37
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -5816,6 +5816,7 @@ declare abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
5816
5816
  private pendingApprovalMessageId;
5817
5817
  private activeResponse;
5818
5818
  private activeResumeRequest;
5819
+ private resumableStreamState;
5819
5820
  private jobExecutor;
5820
5821
  constructor({ generateId, id, transport, messageMetadataSchema, dataPartSchemas, state, onError, onToolCall, onFinish, onData, sendAutomaticallyWhen, }: Omit<ChatInit<UI_MESSAGE>, 'messages'> & {
5821
5822
  state: ChatState<UI_MESSAGE>;
package/dist/index.js CHANGED
@@ -1328,7 +1328,7 @@ import {
1328
1328
  } from "@ai-sdk/provider-utils";
1329
1329
 
1330
1330
  // src/version.ts
1331
- var VERSION = true ? "7.0.118" : "0.0.0-test";
1331
+ var VERSION = true ? "7.0.120" : "0.0.0-test";
1332
1332
 
1333
1333
  // src/util/download/download.ts
1334
1334
  var download = async ({
@@ -5056,6 +5056,8 @@ function openTelemetryChannelSpanContext({
5056
5056
  completion
5057
5057
  }) {
5058
5058
  if (!isNodeRuntime()) {
5059
+ Promise.resolve(completion).catch(() => {
5060
+ });
5059
5061
  return void 0;
5060
5062
  }
5061
5063
  const diagnosticsChannel = loadBuiltinModule(
@@ -7053,11 +7055,26 @@ function writeToServerResponse({
7053
7055
  response.writeHead(statusCode);
7054
7056
  }
7055
7057
  const reader = stream.getReader();
7058
+ let clientDisconnected = false;
7059
+ let onDisconnect;
7060
+ const handleClose = () => {
7061
+ if (response.writableFinished) {
7062
+ return;
7063
+ }
7064
+ clientDisconnected = true;
7065
+ onDisconnect?.();
7066
+ reader.cancel(new Error("Client disconnected.")).catch(() => {
7067
+ });
7068
+ };
7069
+ response.once("close", handleClose);
7070
+ if (response.destroyed) {
7071
+ handleClose();
7072
+ }
7056
7073
  const read = async () => {
7057
7074
  try {
7058
7075
  while (true) {
7059
7076
  const { done, value } = await reader.read();
7060
- if (done) break;
7077
+ if (done || clientDisconnected || response.destroyed) break;
7061
7078
  const canContinue = response.write(value);
7062
7079
  const flush = response.flush;
7063
7080
  if (typeof flush === "function") {
@@ -7065,12 +7082,20 @@ function writeToServerResponse({
7065
7082
  }
7066
7083
  if (!canContinue) {
7067
7084
  await new Promise((resolve3) => {
7085
+ onDisconnect = resolve3;
7068
7086
  response.once("drain", resolve3);
7069
7087
  });
7088
+ onDisconnect = void 0;
7070
7089
  }
7071
7090
  }
7072
7091
  } finally {
7073
- response.end();
7092
+ response.off("close", handleClose);
7093
+ if (clientDisconnected || response.destroyed) {
7094
+ reader.cancel().catch(() => {
7095
+ });
7096
+ } else {
7097
+ response.end();
7098
+ }
7074
7099
  }
7075
7100
  };
7076
7101
  return read();
@@ -7446,25 +7471,6 @@ function getToolName(part) {
7446
7471
  }
7447
7472
  var getToolOrDynamicToolName = getToolName;
7448
7473
 
7449
- // src/ui/warn-if-ui-message-has-deprecated-raw-input.ts
7450
- var rawInputDeprecationWarning = {
7451
- type: "deprecated",
7452
- setting: "rawInput in output-error UI message parts",
7453
- message: 'Use the "input" field instead. The "rawInput" field will be removed in the next major version.'
7454
- };
7455
- function warnIfUIMessageHasDeprecatedRawInput(messages) {
7456
- const hasDeprecatedRawInput = messages.some(
7457
- (message) => message.parts.some(
7458
- (part) => part != null && typeof part === "object" && "type" in part && typeof part.type === "string" && (part.type === "dynamic-tool" || part.type.startsWith("tool-")) && "state" in part && part.state === "output-error" && Object.prototype.hasOwnProperty.call(part, "rawInput") && "rawInput" in part && part.rawInput !== void 0
7459
- )
7460
- );
7461
- if (hasDeprecatedRawInput) {
7462
- logWarnings({
7463
- warnings: [rawInputDeprecationWarning]
7464
- });
7465
- }
7466
- }
7467
-
7468
7474
  // src/ui/process-ui-message-stream.ts
7469
7475
  function createStreamingUIMessageState({
7470
7476
  lastMessage,
@@ -7905,14 +7911,12 @@ function processUIMessageStream({
7905
7911
  toolCallId: chunk.toolCallId,
7906
7912
  toolName: chunk.toolName,
7907
7913
  state: "output-error",
7908
- input: void 0,
7909
- rawInput: chunk.input,
7914
+ input: chunk.input,
7910
7915
  errorText: chunk.errorText,
7911
7916
  providerExecuted: chunk.providerExecuted,
7912
7917
  providerMetadata: chunk.providerMetadata,
7913
7918
  toolMetadata: chunk.toolMetadata
7914
7919
  });
7915
- warnIfUIMessageHasDeprecatedRawInput([state.message]);
7916
7920
  }
7917
7921
  write();
7918
7922
  break;
@@ -7975,7 +7979,7 @@ function processUIMessageStream({
7975
7979
  providerExecuted: chunk.providerExecuted,
7976
7980
  providerMetadata: chunk.providerMetadata,
7977
7981
  title: toolInvocation.title,
7978
- toolMetadata: toolInvocation.toolMetadata
7982
+ toolMetadata: chunk.toolMetadata ?? toolInvocation.toolMetadata
7979
7983
  },
7980
7984
  toolInvocation
7981
7985
  );
@@ -7991,7 +7995,7 @@ function processUIMessageStream({
7991
7995
  preliminary: chunk.preliminary,
7992
7996
  providerMetadata: chunk.providerMetadata,
7993
7997
  title: toolInvocation.title,
7994
- toolMetadata: toolInvocation.toolMetadata
7998
+ toolMetadata: chunk.toolMetadata ?? toolInvocation.toolMetadata
7995
7999
  },
7996
8000
  toolInvocation
7997
8001
  );
@@ -8012,7 +8016,7 @@ function processUIMessageStream({
8012
8016
  providerExecuted: chunk.providerExecuted,
8013
8017
  providerMetadata: chunk.providerMetadata,
8014
8018
  title: toolInvocation.title,
8015
- toolMetadata: toolInvocation.toolMetadata
8019
+ toolMetadata: chunk.toolMetadata ?? toolInvocation.toolMetadata
8016
8020
  },
8017
8021
  toolInvocation
8018
8022
  );
@@ -8028,7 +8032,7 @@ function processUIMessageStream({
8028
8032
  providerExecuted: chunk.providerExecuted,
8029
8033
  providerMetadata: chunk.providerMetadata,
8030
8034
  title: toolInvocation.title,
8031
- toolMetadata: toolInvocation.toolMetadata
8035
+ toolMetadata: chunk.toolMetadata ?? toolInvocation.toolMetadata
8032
8036
  },
8033
8037
  toolInvocation
8034
8038
  );
@@ -12219,6 +12223,27 @@ function readUIMessageStream({
12219
12223
  import {
12220
12224
  isNonNullable
12221
12225
  } from "@ai-sdk/provider-utils";
12226
+
12227
+ // src/ui/warn-if-ui-message-has-deprecated-raw-input.ts
12228
+ var rawInputDeprecationWarning = {
12229
+ type: "deprecated",
12230
+ setting: "rawInput in output-error UI message parts",
12231
+ message: 'Use the "input" field instead. The "rawInput" field will be removed in the next major version.'
12232
+ };
12233
+ function warnIfUIMessageHasDeprecatedRawInput(messages) {
12234
+ const hasDeprecatedRawInput = messages.some(
12235
+ (message) => message.parts.some(
12236
+ (part) => part != null && typeof part === "object" && "type" in part && typeof part.type === "string" && (part.type === "dynamic-tool" || part.type.startsWith("tool-")) && "state" in part && part.state === "output-error" && Object.prototype.hasOwnProperty.call(part, "rawInput") && "rawInput" in part && part.rawInput !== void 0
12237
+ )
12238
+ );
12239
+ if (hasDeprecatedRawInput) {
12240
+ logWarnings({
12241
+ warnings: [rawInputDeprecationWarning]
12242
+ });
12243
+ }
12244
+ }
12245
+
12246
+ // src/ui/convert-to-model-messages.ts
12222
12247
  async function convertToModelMessages(messages, options) {
12223
12248
  const modelMessages = [];
12224
12249
  warnIfUIMessageHasDeprecatedRawInput(messages);
@@ -17874,7 +17899,9 @@ var doWrap3 = ({
17874
17899
  wrapGenerate,
17875
17900
  overrideProvider,
17876
17901
  overrideModelId,
17877
- overrideMaxImagesPerCall
17902
+ overrideMaxImagesPerCall,
17903
+ overrideSupportsFileInputs,
17904
+ overrideSupportsMaskInputs
17878
17905
  },
17879
17906
  modelId,
17880
17907
  providerId
@@ -17884,11 +17911,15 @@ var doWrap3 = ({
17884
17911
  }
17885
17912
  const maxImagesPerCallRaw = overrideMaxImagesPerCall?.({ model }) ?? model.maxImagesPerCall;
17886
17913
  const maxImagesPerCall = maxImagesPerCallRaw instanceof Function ? maxImagesPerCallRaw.bind(model) : maxImagesPerCallRaw;
17914
+ const supportsFileInputs = overrideSupportsFileInputs !== void 0 ? overrideSupportsFileInputs({ model }) : model.supportsFileInputs;
17915
+ const supportsMaskInputs = overrideSupportsMaskInputs !== void 0 ? overrideSupportsMaskInputs({ model }) : model.supportsMaskInputs;
17887
17916
  return {
17888
17917
  specificationVersion: "v4",
17889
17918
  provider: providerId ?? overrideProvider?.({ model }) ?? model.provider,
17890
17919
  modelId: modelId ?? overrideModelId?.({ model }) ?? model.modelId,
17891
17920
  maxImagesPerCall,
17921
+ supportsFileInputs,
17922
+ supportsMaskInputs,
17892
17923
  async doGenerate(params) {
17893
17924
  const transformedParams = await doTransform({ params });
17894
17925
  const doGenerate = async () => await model.doGenerate(transformedParams);
@@ -21976,6 +22007,7 @@ var AbstractChat = class {
21976
22007
  this.pendingMessagePreparations = /* @__PURE__ */ new Set();
21977
22008
  this.activeResponse = void 0;
21978
22009
  this.activeResumeRequest = void 0;
22010
+ this.resumableStreamState = void 0;
21979
22011
  this.jobExecutor = new SerialJobExecutor();
21980
22012
  /**
21981
22013
  * Appends or replaces a user message to the chat list. This triggers the API call to fetch
@@ -22270,6 +22302,9 @@ var AbstractChat = class {
22270
22302
  body,
22271
22303
  messageId
22272
22304
  }) {
22305
+ if (trigger !== "resume-stream") {
22306
+ this.resumableStreamState = void 0;
22307
+ }
22273
22308
  const abortController = new AbortController();
22274
22309
  const activeResumeRequest = trigger === "resume-stream" ? { abortController } : void 0;
22275
22310
  if (activeResumeRequest) {
@@ -22297,12 +22332,14 @@ var AbstractChat = class {
22297
22332
  });
22298
22333
  if (isCurrentRequest()) {
22299
22334
  this.setStatus({ status: "ready" });
22335
+ this.resumableStreamState = void 0;
22300
22336
  }
22301
22337
  clearActiveResumeRequest();
22302
22338
  return;
22303
22339
  }
22304
22340
  if (reconnect == null) {
22305
22341
  this.setStatus({ status: "ready" });
22342
+ this.resumableStreamState = void 0;
22306
22343
  clearActiveResumeRequest();
22307
22344
  return;
22308
22345
  }
@@ -22311,6 +22348,7 @@ var AbstractChat = class {
22311
22348
  if (abortController.signal.aborted || err.name === "AbortError") {
22312
22349
  if (isCurrentRequest()) {
22313
22350
  this.setStatus({ status: "ready" });
22351
+ this.resumableStreamState = void 0;
22314
22352
  }
22315
22353
  clearActiveResumeRequest();
22316
22354
  return;
@@ -22337,7 +22375,7 @@ var AbstractChat = class {
22337
22375
  let activeResponse;
22338
22376
  try {
22339
22377
  const response = {
22340
- state: createStreamingUIMessageState({
22378
+ state: trigger === "resume-stream" && this.resumableStreamState != null ? this.resumableStreamState : createStreamingUIMessageState({
22341
22379
  lastMessage: trigger === "resume-stream" || trigger === "regenerate-message" ? void 0 : this.state.snapshot(responseMessage),
22342
22380
  messageId: this.generateId()
22343
22381
  }),
@@ -22415,17 +22453,26 @@ var AbstractChat = class {
22415
22453
  if (isAbort) {
22416
22454
  if (isCurrentRequest()) {
22417
22455
  this.setStatus({ status: "ready" });
22456
+ if (this.resumableStreamState === response.state) {
22457
+ this.resumableStreamState = void 0;
22458
+ }
22418
22459
  }
22419
22460
  return null;
22420
22461
  }
22421
22462
  if (isCurrentRequest()) {
22422
22463
  this.setStatus({ status: "ready" });
22464
+ if (this.resumableStreamState === response.state) {
22465
+ this.resumableStreamState = void 0;
22466
+ }
22423
22467
  }
22424
22468
  } catch (err) {
22425
22469
  if (isAbort || err.name === "AbortError") {
22426
22470
  isAbort = true;
22427
22471
  if (isCurrentRequest()) {
22428
22472
  this.setStatus({ status: "ready" });
22473
+ if (this.resumableStreamState === activeResponse?.state) {
22474
+ this.resumableStreamState = void 0;
22475
+ }
22429
22476
  }
22430
22477
  return null;
22431
22478
  }
@@ -22436,6 +22483,11 @@ var AbstractChat = class {
22436
22483
  if (err instanceof TypeError && (err.message.toLowerCase().includes("fetch") || err.message.toLowerCase().includes("network"))) {
22437
22484
  isDisconnect = true;
22438
22485
  }
22486
+ if (isDisconnect) {
22487
+ this.resumableStreamState = activeResponse?.state;
22488
+ } else if (this.resumableStreamState === activeResponse?.state) {
22489
+ this.resumableStreamState = void 0;
22490
+ }
22439
22491
  if (this.onError && err instanceof Error) {
22440
22492
  this.onError(err);
22441
22493
  }