ai 7.0.18 → 7.0.20

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 (56) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/index.d.ts +58 -5
  3. package/dist/index.js +168 -79
  4. package/dist/index.js.map +1 -1
  5. package/dist/internal/index.js +43 -31
  6. package/dist/internal/index.js.map +1 -1
  7. package/docs/02-foundations/02-providers-and-models.mdx +57 -52
  8. package/docs/02-getting-started/00-choosing-a-provider.mdx +1 -16
  9. package/docs/02-getting-started/01-navigating-the-library.mdx +12 -12
  10. package/docs/02-getting-started/02-nextjs-app-router.mdx +2 -36
  11. package/docs/02-getting-started/03-nextjs-pages-router.mdx +2 -36
  12. package/docs/02-getting-started/04-svelte.mdx +2 -34
  13. package/docs/02-getting-started/05-nuxt.mdx +2 -36
  14. package/docs/02-getting-started/06-nodejs.mdx +1 -18
  15. package/docs/02-getting-started/07-expo.mdx +3 -62
  16. package/docs/02-getting-started/08-tanstack-start.mdx +2 -36
  17. package/docs/02-getting-started/09-coding-agents.mdx +2 -32
  18. package/docs/03-agents/07-workflow-agent.mdx +1 -1
  19. package/docs/03-ai-sdk-core/15-tools-and-tool-calling.mdx +3 -12
  20. package/docs/03-ai-sdk-core/16-mcp-tools.mdx +44 -0
  21. package/docs/03-ai-sdk-core/30-embeddings.mdx +18 -18
  22. package/docs/03-ai-sdk-core/38-video-generation.mdx +22 -3
  23. package/docs/03-ai-sdk-harnesses/02-harness-agent.mdx +1 -28
  24. package/docs/03-ai-sdk-harnesses/05-harness-adapters.mdx +7 -7
  25. package/docs/03-ai-sdk-harnesses/06-workflow-utilities.mdx +1 -16
  26. package/docs/03-ai-sdk-harnesses/08-terminal-ui.mdx +1 -28
  27. package/docs/04-ai-sdk-ui/01-overview.mdx +5 -5
  28. package/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx +1 -1
  29. package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +1 -1
  30. package/docs/07-reference/01-ai-sdk-core/13-generate-video.mdx +3 -2
  31. package/docs/07-reference/01-ai-sdk-core/16-tool-loop-agent.mdx +1 -1
  32. package/docs/07-reference/02-ai-sdk-ui/index.mdx +5 -5
  33. package/docs/07-reference/04-ai-sdk-workflow/01-workflow-agent.mdx +2 -2
  34. package/package.json +4 -4
  35. package/src/agent/tool-loop-agent-settings.ts +7 -0
  36. package/src/generate-text/collect-tool-approvals.ts +17 -4
  37. package/src/generate-text/execute-tool-call.ts +3 -2
  38. package/src/generate-text/execute-tools-from-stream.ts +2 -1
  39. package/src/generate-text/generate-text.ts +14 -5
  40. package/src/generate-text/index.ts +1 -0
  41. package/src/generate-text/invoke-tool-callbacks-from-stream.ts +6 -4
  42. package/src/generate-text/parse-tool-call.ts +5 -4
  43. package/src/generate-text/resolve-tool-approval.ts +9 -6
  44. package/src/generate-text/stream-language-model-call.ts +2 -1
  45. package/src/generate-text/stream-text.ts +12 -3
  46. package/src/generate-text/to-response-messages.ts +4 -3
  47. package/src/generate-text/tool-approval-signature.ts +4 -40
  48. package/src/generate-text/tool-fingerprint.ts +76 -0
  49. package/src/generate-text/validate-tool-approvals.ts +6 -1
  50. package/src/generate-video/generate-video.ts +96 -21
  51. package/src/ui/convert-to-model-messages.ts +3 -2
  52. package/src/ui/process-ui-message-stream.ts +3 -0
  53. package/src/ui/validate-ui-messages.ts +2 -1
  54. package/src/util/canonical-hash.ts +44 -0
  55. package/src/util/get-own.ts +18 -0
  56. package/src/util/write-to-server-response.ts +9 -0
@@ -11,6 +11,7 @@ import {
11
11
  } from '@ai-sdk/provider-utils';
12
12
  import { createToolModelOutput } from '../prompt/create-tool-model-output';
13
13
  import { MessageConversionError } from '../prompt/message-conversion-error';
14
+ import { getOwn } from '../util/get-own';
14
15
  import {
15
16
  getToolName,
16
17
  isCustomContentUIPart,
@@ -256,7 +257,7 @@ export async function convertToModelMessages<UI_MESSAGE extends UIMessage>(
256
257
  part.state === 'output-error'
257
258
  ? part.errorText
258
259
  : part.output,
259
- tool: options?.tools?.[toolName],
260
+ tool: getOwn(options?.tools, toolName),
260
261
  errorMode:
261
262
  part.state === 'output-error' ? 'json' : 'none',
262
263
  }),
@@ -375,7 +376,7 @@ export async function convertToModelMessages<UI_MESSAGE extends UIMessage>(
375
376
  toolPart.state === 'output-error'
376
377
  ? toolPart.errorText
377
378
  : toolPart.output,
378
- tool: options?.tools?.[toolName],
379
+ tool: getOwn(options?.tools, toolName),
379
380
  errorMode:
380
381
  toolPart.state === 'output-error' ? 'text' : 'none',
381
382
  }),
@@ -731,6 +731,9 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
731
731
  approved: chunk.approved,
732
732
  ...(chunk.reason != null ? { reason: chunk.reason } : {}),
733
733
  ...(approval.isAutomatic === true ? { isAutomatic: true } : {}),
734
+ ...(approval.signature != null
735
+ ? { signature: approval.signature }
736
+ : {}),
734
737
  };
735
738
  if (chunk.providerExecuted != null) {
736
739
  toolInvocation.providerExecuted = chunk.providerExecuted;
@@ -9,6 +9,7 @@ import {
9
9
  import { z } from 'zod/v4';
10
10
  import { InvalidArgumentError } from '../error';
11
11
  import { jsonValueSchema } from '../types/json-value';
12
+ import { getOwn } from '../util/get-own';
12
13
  import { providerMetadataSchema } from '../types/provider-metadata';
13
14
  import type {
14
15
  DataUIPart,
@@ -456,7 +457,7 @@ export async function safeValidateUIMessages<UI_MESSAGE extends UIMessage>({
456
457
  InferUIMessageTools<UI_MESSAGE>
457
458
  >;
458
459
  const toolName = toolPart.type.slice(5);
459
- const tool = tools[toolName];
460
+ const tool = getOwn(tools, toolName);
460
461
 
461
462
  if (
462
463
  !tool &&
@@ -0,0 +1,44 @@
1
+ import { convertUint8ArrayToBase64 } from '@ai-sdk/provider-utils';
2
+
3
+ const encoder = new TextEncoder();
4
+
5
+ /**
6
+ * Deterministic JSON serialization: object keys are sorted so that two
7
+ * structurally-equal values always produce the same string regardless of key
8
+ * insertion order. Used as the input to content hashing.
9
+ */
10
+ export function canonicalJSON(value: unknown): string {
11
+ if (value === null || value === undefined) {
12
+ return JSON.stringify(value);
13
+ }
14
+ if (typeof value !== 'object') {
15
+ return JSON.stringify(value);
16
+ }
17
+ if (Array.isArray(value)) {
18
+ return `[${value.map(canonicalJSON).join(',')}]`;
19
+ }
20
+ const keys = Object.keys(value as Record<string, unknown>).sort();
21
+ const entries = keys.map(
22
+ k =>
23
+ `${JSON.stringify(k)}:${canonicalJSON((value as Record<string, unknown>)[k])}`,
24
+ );
25
+ return `{${entries.join(',')}}`;
26
+ }
27
+
28
+ export function toBase64url(bytes: Uint8Array): string {
29
+ return convertUint8ArrayToBase64(bytes)
30
+ .replace(/\+/g, '-')
31
+ .replace(/\//g, '_')
32
+ .replace(/=+$/g, '');
33
+ }
34
+
35
+ /**
36
+ * Canonical SHA-256 digest (base64url) of an arbitrary JSON-serializable value.
37
+ */
38
+ export async function hashCanonical(value: unknown): Promise<string> {
39
+ const digest = await crypto.subtle.digest(
40
+ 'SHA-256',
41
+ encoder.encode(canonicalJSON(value)),
42
+ );
43
+ return toBase64url(new Uint8Array(digest));
44
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Reads a property by an untrusted key, ignoring inherited prototype members.
3
+ *
4
+ * Tool sets, tool contexts, and similar lookup objects are indexed by names
5
+ * that can come from model output or client-supplied message history. Plain
6
+ * bracket access (`obj[name]`) resolves names such as `constructor`,
7
+ * `toString`, or `__proto__` to values on `Object.prototype`, which would slip
8
+ * past the `== null` / `!value` guards that treat an unknown name as "not
9
+ * present". This helper returns `undefined` unless `key` is an own property.
10
+ */
11
+ export function getOwn<T extends object>(
12
+ obj: T | undefined | null,
13
+ key: string,
14
+ ): T[keyof T] | undefined {
15
+ return obj != null && Object.hasOwn(obj, key)
16
+ ? obj[key as keyof T]
17
+ : undefined;
18
+ }
@@ -1,5 +1,9 @@
1
1
  import type { ServerResponse } from 'node:http';
2
2
 
3
+ type FlushableServerResponse = ServerResponse & {
4
+ flush?: () => void;
5
+ };
6
+
3
7
  /**
4
8
  * Writes the content of a stream to a server response.
5
9
  */
@@ -32,6 +36,11 @@ export function writeToServerResponse({
32
36
 
33
37
  // Respect backpressure: if write() returns false, wait for 'drain' event
34
38
  const canContinue = response.write(value);
39
+ const flush = (response as FlushableServerResponse).flush;
40
+ if (typeof flush === 'function') {
41
+ flush.call(response);
42
+ }
43
+
35
44
  if (!canContinue) {
36
45
  await new Promise<void>(resolve => {
37
46
  response.once('drain', resolve);