ai 7.0.0-beta.90 → 7.0.0-beta.92

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # ai
2
2
 
3
+ ## 7.0.0-beta.92
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [ba2e254]
8
+ - @ai-sdk/gateway@4.0.0-beta.52
9
+
10
+ ## 7.0.0-beta.91
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies [cdcdec2]
15
+ - @ai-sdk/gateway@4.0.0-beta.51
16
+
3
17
  ## 7.0.0-beta.90
4
18
 
5
19
  ### Patch Changes
package/dist/index.js CHANGED
@@ -1380,7 +1380,7 @@ import {
1380
1380
  } from "@ai-sdk/provider-utils";
1381
1381
 
1382
1382
  // src/version.ts
1383
- var VERSION = true ? "7.0.0-beta.90" : "0.0.0-test";
1383
+ var VERSION = true ? "7.0.0-beta.92" : "0.0.0-test";
1384
1384
 
1385
1385
  // src/util/download/download.ts
1386
1386
  var download = async ({
@@ -196,7 +196,7 @@ import {
196
196
  } from "@ai-sdk/provider-utils";
197
197
 
198
198
  // src/version.ts
199
- var VERSION = true ? "7.0.0-beta.90" : "0.0.0-test";
199
+ var VERSION = true ? "7.0.0-beta.92" : "0.0.0-test";
200
200
 
201
201
  // src/util/download/download.ts
202
202
  var download = async ({
@@ -20,17 +20,16 @@ A standard `ToolLoopAgent` runs entirely in memory — if the process crashes, a
20
20
 
21
21
  ## When to Use WorkflowAgent vs ToolLoopAgent
22
22
 
23
- | | ToolLoopAgent | WorkflowAgent |
24
- |---|---|---|
25
- | **Package** | `ai` | `@ai-sdk/workflow` |
26
- | **Runtime** | In-memory | Vercel Workflow |
27
- | **Durability** | Lost on crash | Survives restarts |
28
- | **Tool retries** | Manual | Automatic (via workflow steps) |
29
- | **Human approval** | Built-in | Built-in + survives suspension |
30
- | **`generate()` method** | Available | Not available |
31
- | **`stream()` method** | Available | Primary API |
32
- | **Model as string** | Not supported | AI Gateway string IDs |
33
- | **Stream output** | `streamText` return value | `writable` parameter with `ModelCallStreamPart` |
23
+ | | ToolLoopAgent | WorkflowAgent |
24
+ | ----------------------- | ------------------------- | ----------------------------------------------- |
25
+ | **Package** | `ai` | `@ai-sdk/workflow` |
26
+ | **Runtime** | In-memory | Vercel Workflow |
27
+ | **Durability** | Lost on crash | Survives restarts |
28
+ | **Tool retries** | Manual | Automatic (via workflow steps) |
29
+ | **Human approval** | Built-in | Built-in + survives suspension |
30
+ | **`generate()` method** | Available | Not available |
31
+ | **`stream()` method** | Available | Primary API |
32
+ | **Stream output** | `streamText` return value | `writable` parameter with `ModelCallStreamPart` |
34
33
 
35
34
  For simpler use cases that don't need durability, use [`ToolLoopAgent`](/docs/agents/building-agents) from the `ai` package.
36
35
 
@@ -47,16 +46,16 @@ npm install @ai-sdk/workflow workflow
47
46
  Define an agent by instantiating the `WorkflowAgent` class with a model, instructions, and tools:
48
47
 
49
48
  ```ts
50
- import { WorkflowAgent } from '@ai-sdk/workflow';
51
- import { tool } from 'ai';
52
- import { z } from 'zod';
49
+ import { WorkflowAgent } from "@ai-sdk/workflow";
50
+ import { tool } from "ai";
51
+ import { z } from "zod";
53
52
 
54
53
  const agent = new WorkflowAgent({
55
- model: 'anthropic/claude-sonnet-4-6',
56
- instructions: 'You are a helpful assistant.',
54
+ model: "anthropic/claude-sonnet-4-6",
55
+ instructions: "You are a helpful assistant.",
57
56
  tools: {
58
57
  weather: tool({
59
- description: 'Get weather for a location',
58
+ description: "Get weather for a location",
60
59
  inputSchema: z.object({
61
60
  location: z.string(),
62
61
  }),
@@ -71,23 +70,15 @@ const agent = new WorkflowAgent({
71
70
 
72
71
  ### Model Resolution
73
72
 
74
- The `model` parameter accepts three forms:
73
+ The `model` parameter accepts two forms:
75
74
 
76
75
  ```ts
77
76
  // String — AI Gateway model ID
78
- new WorkflowAgent({ model: 'anthropic/claude-sonnet-4-6' });
77
+ new WorkflowAgent({ model: "anthropic/claude-sonnet-4-6" });
79
78
 
80
79
  // Provider instance
81
- import { openai } from '@ai-sdk/openai';
82
- new WorkflowAgent({ model: openai('gpt-4o') });
83
-
84
- // Async function — resolved inside the workflow step
85
- new WorkflowAgent({
86
- model: async () => {
87
- const { openai } = await import('@ai-sdk/openai');
88
- return openai('gpt-4o');
89
- },
90
- });
80
+ import { openai } from "@ai-sdk/openai";
81
+ new WorkflowAgent({ model: openai("gpt-4o") });
91
82
  ```
92
83
 
93
84
  ## Using the Agent in a Workflow
@@ -101,22 +92,22 @@ new WorkflowAgent({
101
92
  ### End-to-End Example
102
93
 
103
94
  ```ts filename="workflow/agent-chat.ts"
104
- import { WorkflowAgent, type ModelCallStreamPart } from '@ai-sdk/workflow';
105
- import { convertToModelMessages, tool, type UIMessage } from 'ai';
106
- import { getWritable } from 'workflow';
107
- import { z } from 'zod';
95
+ import { WorkflowAgent, type ModelCallStreamPart } from "@ai-sdk/workflow";
96
+ import { convertToModelMessages, tool, type UIMessage } from "ai";
97
+ import { getWritable } from "workflow";
98
+ import { z } from "zod";
108
99
 
109
100
  export async function chat(messages: UIMessage[]) {
110
- 'use workflow';
101
+ "use workflow";
111
102
 
112
103
  const modelMessages = await convertToModelMessages(messages);
113
104
 
114
105
  const agent = new WorkflowAgent({
115
- model: 'anthropic/claude-sonnet-4-6',
116
- instructions: 'You are a flight booking assistant.',
106
+ model: "anthropic/claude-sonnet-4-6",
107
+ instructions: "You are a flight booking assistant.",
117
108
  tools: {
118
109
  searchFlights: tool({
119
- description: 'Search for available flights',
110
+ description: "Search for available flights",
120
111
  inputSchema: z.object({
121
112
  origin: z.string(),
122
113
  destination: z.string(),
@@ -125,7 +116,7 @@ export async function chat(messages: UIMessage[]) {
125
116
  execute: searchFlightsStep,
126
117
  }),
127
118
  bookFlight: tool({
128
- description: 'Book a specific flight',
119
+ description: "Book a specific flight",
129
120
  inputSchema: z.object({
130
121
  flightId: z.string(),
131
122
  passengerName: z.string(),
@@ -145,10 +136,10 @@ export async function chat(messages: UIMessage[]) {
145
136
  ```
146
137
 
147
138
  ```ts filename="app/api/chat/route.ts"
148
- import { createModelCallToUIChunkTransform } from '@ai-sdk/workflow';
149
- import { createUIMessageStreamResponse, type UIMessage } from 'ai';
150
- import { start } from 'workflow/api';
151
- import { chat } from '@/workflow/agent-chat';
139
+ import { createModelCallToUIChunkTransform } from "@ai-sdk/workflow";
140
+ import { createUIMessageStreamResponse, type UIMessage } from "ai";
141
+ import { start } from "workflow/api";
142
+ import { chat } from "@/workflow/agent-chat";
152
143
 
153
144
  export async function POST(request: Request) {
154
145
  const { messages }: { messages: UIMessage[] } = await request.json();
@@ -166,10 +157,10 @@ export async function POST(request: Request) {
166
157
  `WorkflowAgent.stream()` expects `ModelMessage[]`, not `UIMessage[]`. When receiving messages from the client (via `useChat`), convert them first:
167
158
 
168
159
  ```ts
169
- import { convertToModelMessages, type UIMessage } from 'ai';
160
+ import { convertToModelMessages, type UIMessage } from "ai";
170
161
 
171
162
  export async function chat(messages: UIMessage[]) {
172
- 'use workflow';
163
+ "use workflow";
173
164
 
174
165
  const modelMessages = await convertToModelMessages(messages);
175
166
 
@@ -185,8 +176,8 @@ export async function chat(messages: UIMessage[]) {
185
176
  Unlike `ToolLoopAgent` where you consume the returned stream, `WorkflowAgent` writes raw `ModelCallStreamPart` chunks to a `writable` stream provided by the workflow runtime via `getWritable()`. At the response boundary, use `createModelCallToUIChunkTransform()` to convert these into `UIMessageChunk` objects for the client:
186
177
 
187
178
  ```ts
188
- import { createModelCallToUIChunkTransform } from '@ai-sdk/workflow';
189
- import { createUIMessageStreamResponse } from 'ai';
179
+ import { createModelCallToUIChunkTransform } from "@ai-sdk/workflow";
180
+ import { createUIMessageStreamResponse } from "ai";
190
181
 
191
182
  // Convert raw model stream parts → UI message chunks
192
183
  return createUIMessageStreamResponse({
@@ -199,17 +190,17 @@ return createUIMessageStreamResponse({
199
190
  Workflow functions can time out or be interrupted by network failures. `WorkflowChatTransport` is a [`ChatTransport`](/docs/ai-sdk-ui/transport) implementation that handles these interruptions automatically — it detects when a stream ends without a `finish` event and reconnects to resume from where it left off.
200
191
 
201
192
  ```tsx filename="app/page.tsx"
202
- 'use client';
193
+ "use client";
203
194
 
204
- import { useChat } from '@ai-sdk/react';
205
- import { WorkflowChatTransport } from '@ai-sdk/workflow';
206
- import { useMemo } from 'react';
195
+ import { useChat } from "@ai-sdk/react";
196
+ import { WorkflowChatTransport } from "@ai-sdk/workflow";
197
+ import { useMemo } from "react";
207
198
 
208
199
  export default function Chat() {
209
200
  const transport = useMemo(
210
201
  () =>
211
202
  new WorkflowChatTransport({
212
- api: '/api/chat',
203
+ api: "/api/chat",
213
204
  maxConsecutiveErrors: 5,
214
205
  initialStartIndex: -50, // On page refresh, fetch last 50 chunks
215
206
  }),
@@ -225,10 +216,10 @@ export default function Chat() {
225
216
  The transport requires your POST endpoint to return an `x-workflow-run-id` response header, and a GET endpoint at `{api}/{runId}/stream` for reconnection:
226
217
 
227
218
  ```ts filename="app/api/chat/route.ts"
228
- import { createModelCallToUIChunkTransform } from '@ai-sdk/workflow';
229
- import { createUIMessageStreamResponse, type UIMessage } from 'ai';
230
- import { start } from 'workflow/api';
231
- import { chat } from '@/workflow/agent-chat';
219
+ import { createModelCallToUIChunkTransform } from "@ai-sdk/workflow";
220
+ import { createUIMessageStreamResponse, type UIMessage } from "ai";
221
+ import { start } from "workflow/api";
222
+ import { chat } from "@/workflow/agent-chat";
232
223
 
233
224
  export async function POST(request: Request) {
234
225
  const { messages }: { messages: UIMessage[] } = await request.json();
@@ -237,16 +228,16 @@ export async function POST(request: Request) {
237
228
  return createUIMessageStreamResponse({
238
229
  stream: run.readable.pipeThrough(createModelCallToUIChunkTransform()),
239
230
  headers: {
240
- 'x-workflow-run-id': run.runId,
231
+ "x-workflow-run-id": run.runId,
241
232
  },
242
233
  });
243
234
  }
244
235
  ```
245
236
 
246
237
  ```ts filename="app/api/chat/[runId]/stream/route.ts"
247
- import { createModelCallToUIChunkTransform } from '@ai-sdk/workflow';
248
- import type { NextRequest } from 'next/server';
249
- import { getRun } from 'workflow/api';
238
+ import { createModelCallToUIChunkTransform } from "@ai-sdk/workflow";
239
+ import type { NextRequest } from "next/server";
240
+ import { getRun } from "workflow/api";
250
241
 
251
242
  export async function GET(
252
243
  request: NextRequest,
@@ -254,7 +245,7 @@ export async function GET(
254
245
  ) {
255
246
  const { runId } = await params;
256
247
  const startIndex = Number(
257
- new URL(request.url).searchParams.get('startIndex') ?? '0',
248
+ new URL(request.url).searchParams.get("startIndex") ?? "0",
258
249
  );
259
250
 
260
251
  const run = await getRun(runId);
@@ -264,10 +255,10 @@ export async function GET(
264
255
 
265
256
  return new Response(readable, {
266
257
  headers: {
267
- 'Content-Type': 'text/event-stream',
268
- 'Cache-Control': 'no-cache',
269
- Connection: 'keep-alive',
270
- 'x-workflow-run-id': runId,
258
+ "Content-Type": "text/event-stream",
259
+ "Cache-Control": "no-cache",
260
+ Connection: "keep-alive",
261
+ "x-workflow-run-id": runId,
271
262
  },
272
263
  });
273
264
  }
@@ -289,7 +280,7 @@ async function searchFlightsStep(input: {
289
280
  destination: string;
290
281
  date: string;
291
282
  }) {
292
- 'use step';
283
+ "use step";
293
284
  const response = await fetch(`https://api.flights.example/search?...`);
294
285
  return response.json();
295
286
  }
@@ -298,9 +289,9 @@ async function bookFlightStep(input: {
298
289
  flightId: string;
299
290
  passengerName: string;
300
291
  }) {
301
- 'use step';
302
- const response = await fetch('https://api.flights.example/book', {
303
- method: 'POST',
292
+ "use step";
293
+ const response = await fetch("https://api.flights.example/book", {
294
+ method: "POST",
304
295
  body: JSON.stringify(input),
305
296
  });
306
297
  return response.json();
@@ -315,10 +306,10 @@ Tools can require human approval before execution. When a tool has `needsApprova
315
306
 
316
307
  ```ts
317
308
  const agent = new WorkflowAgent({
318
- model: 'anthropic/claude-sonnet-4-6',
309
+ model: "anthropic/claude-sonnet-4-6",
319
310
  tools: {
320
311
  bookFlight: tool({
321
- description: 'Book a flight',
312
+ description: "Book a flight",
322
313
  inputSchema: z.object({
323
314
  flightId: z.string(),
324
315
  passengerName: z.string(),
@@ -327,11 +318,11 @@ const agent = new WorkflowAgent({
327
318
  execute: bookFlightStep,
328
319
  }),
329
320
  cancelBooking: tool({
330
- description: 'Cancel a booking',
321
+ description: "Cancel a booking",
331
322
  inputSchema: z.object({ bookingId: z.string() }),
332
323
  // Conditional approval based on input
333
324
  needsApproval: async (input) => {
334
- return input.bookingId.startsWith('VIP-');
325
+ return input.bookingId.startsWith("VIP-");
335
326
  },
336
327
  execute: cancelBookingStep,
337
328
  }),
@@ -346,11 +337,11 @@ Because the workflow is durable, the approval request survives process restarts
346
337
  Control how many steps the agent can take:
347
338
 
348
339
  ```ts
349
- import { isStepCount } from 'ai';
340
+ import { isStepCount } from "ai";
350
341
 
351
342
  const result = await agent.stream({
352
343
  messages,
353
- maxSteps: 10, // Maximum number of LLM calls
344
+ maxSteps: 10, // Maximum number of LLM calls
354
345
  stopWhen: isStepCount(5), // Or use stop conditions from AI SDK
355
346
  });
356
347
  ```
@@ -362,14 +353,14 @@ By default, the agent loops until the model stops calling tools (no maximum).
362
353
  Parse agent responses into typed objects using `Output`:
363
354
 
364
355
  ```ts
365
- import { Output } from '@ai-sdk/workflow';
366
- import { z } from 'zod';
356
+ import { Output } from "@ai-sdk/workflow";
357
+ import { z } from "zod";
367
358
 
368
359
  const result = await agent.stream({
369
360
  messages,
370
361
  output: Output.object({
371
362
  schema: z.object({
372
- sentiment: z.enum(['positive', 'neutral', 'negative']),
363
+ sentiment: z.enum(["positive", "neutral", "negative"]),
373
364
  summary: z.string(),
374
365
  }),
375
366
  }),
@@ -388,7 +379,7 @@ Called once before the agent loop starts. Use it to transform model, instruction
388
379
 
389
380
  ```ts
390
381
  const agent = new WorkflowAgent({
391
- model: 'anthropic/claude-sonnet-4-6',
382
+ model: "anthropic/claude-sonnet-4-6",
392
383
  prepareCall: async ({ model, tools, messages }) => {
393
384
  return {
394
385
  instructions: `Current time: ${new Date().toISOString()}`,
@@ -403,10 +394,10 @@ Called before each step (LLM call). Use it to modify settings, manage context, o
403
394
 
404
395
  ```ts
405
396
  const agent = new WorkflowAgent({
406
- model: 'anthropic/claude-sonnet-4-6',
397
+ model: "anthropic/claude-sonnet-4-6",
407
398
  prepareStep: async ({ stepNumber, messages }) => {
408
399
  if (stepNumber > 5) {
409
- return { toolChoice: 'none' }; // Force text response after 5 steps
400
+ return { toolChoice: "none" }; // Force text response after 5 steps
410
401
  }
411
402
  return {};
412
403
  },
@@ -421,10 +412,10 @@ Agents provide lifecycle callbacks for logging, observability, and custom teleme
421
412
 
422
413
  ```ts
423
414
  const agent = new WorkflowAgent({
424
- model: 'anthropic/claude-sonnet-4-6',
415
+ model: "anthropic/claude-sonnet-4-6",
425
416
 
426
417
  experimental_onStart({ model, messages }) {
427
- console.log('Agent started');
418
+ console.log("Agent started");
428
419
  },
429
420
 
430
421
  experimental_onStepStart({ stepNumber }) {
@@ -440,7 +431,7 @@ const agent = new WorkflowAgent({
440
431
  },
441
432
 
442
433
  onStepFinish({ usage, finishReason }) {
443
- console.log('Step done:', { finishReason });
434
+ console.log("Step done:", { finishReason });
444
435
  },
445
436
 
446
437
  onFinish({ steps, totalUsage }) {
@@ -454,7 +445,7 @@ const agent = new WorkflowAgent({
454
445
  Infer the UI message type for type-safe client components:
455
446
 
456
447
  ```ts
457
- import { WorkflowAgent, InferWorkflowAgentUIMessage } from '@ai-sdk/workflow';
448
+ import { WorkflowAgent, InferWorkflowAgentUIMessage } from "@ai-sdk/workflow";
458
449
 
459
450
  const myAgent = new WorkflowAgent({
460
451
  // ... configuration
@@ -636,6 +636,23 @@ To see `ToolLoopAgent` in action, check out [these examples](#examples).
636
636
  ]}
637
637
  />
638
638
 
639
+ ## Properties
640
+
641
+ <PropertiesTable
642
+ content={[
643
+ {
644
+ name: 'tools',
645
+ type: 'Record<string, Tool>',
646
+ description: 'The tool set configured for this agent. Read-only.',
647
+ },
648
+ {
649
+ name: 'id',
650
+ type: 'string | undefined',
651
+ description: 'The agent identifier, if one was provided in the constructor.',
652
+ },
653
+ ]}
654
+ />
655
+
639
656
  ## Methods
640
657
 
641
658
  ### `generate()`
@@ -52,10 +52,10 @@ To see `WorkflowAgent` in action, check out [these examples](#examples).
52
52
  content={[
53
53
  {
54
54
  name: 'model',
55
- type: 'string | CompatibleLanguageModel | (() => Promise<CompatibleLanguageModel>)',
55
+ type: 'LanguageModel',
56
56
  isRequired: true,
57
57
  description:
58
- 'The model to use. A string compatible with the Vercel AI Gateway (e.g., \'anthropic/claude-sonnet-4-6\'), a LanguageModelV4 instance, or an async function returning one.',
58
+ 'The language model to use. A string compatible with the Vercel AI Gateway (e.g., \'anthropic/claude-sonnet-4-6\') or a provider instance (e.g., `openai(\'gpt-4o\')`).',
59
59
  },
60
60
  {
61
61
  name: 'instructions',
@@ -118,7 +118,7 @@ To see `WorkflowAgent` in action, check out [these examples](#examples).
118
118
  parameters: [
119
119
  {
120
120
  name: 'model',
121
- type: 'string | CompatibleLanguageModel | (() => Promise<CompatibleLanguageModel>)',
121
+ type: 'LanguageModel',
122
122
  description: 'The model being used for the generation.',
123
123
  },
124
124
  {
@@ -147,7 +147,7 @@ To see `WorkflowAgent` in action, check out [these examples](#examples).
147
147
  },
148
148
  {
149
149
  name: 'model',
150
- type: 'string | CompatibleLanguageModel | (() => Promise<CompatibleLanguageModel>)',
150
+ type: 'LanguageModel',
151
151
  description: 'The model being used for this step.',
152
152
  },
153
153
  {
@@ -209,14 +209,14 @@ To see `WorkflowAgent` in action, check out [these examples](#examples).
209
209
  },
210
210
  {
211
211
  name: 'onStepFinish',
212
- type: 'StreamTextOnStepFinishCallback',
212
+ type: 'WorkflowAgentOnStepFinishCallback',
213
213
  isOptional: true,
214
214
  description:
215
215
  'Callback invoked after each agent step completes. If also specified in `stream()`, both callbacks fire (constructor first).',
216
216
  },
217
217
  {
218
218
  name: 'onFinish',
219
- type: 'StreamTextOnFinishCallback',
219
+ type: 'WorkflowAgentOnFinishCallback',
220
220
  isOptional: true,
221
221
  description:
222
222
  'Callback called when all agent steps are finished and the response is complete. Receives steps, messages, text, finish reason, total usage, and context. If also specified in `stream()`, both callbacks fire (constructor first).',
@@ -456,27 +456,27 @@ const result = await agent.stream({
456
456
  },
457
457
  {
458
458
  name: 'onStepFinish',
459
- type: 'StreamTextOnStepFinishCallback',
459
+ type: 'WorkflowAgentOnStepFinishCallback',
460
460
  isOptional: true,
461
461
  description:
462
462
  'Per-call onStepFinish callback. If also specified in the constructor, both fire (constructor first).',
463
463
  },
464
464
  {
465
465
  name: 'onFinish',
466
- type: 'StreamTextOnFinishCallback',
466
+ type: 'WorkflowAgentOnFinishCallback',
467
467
  isOptional: true,
468
468
  description:
469
469
  'Per-call onFinish callback. If also specified in the constructor, both fire (constructor first).',
470
470
  },
471
471
  {
472
472
  name: 'onError',
473
- type: 'StreamTextOnErrorCallback',
473
+ type: 'WorkflowAgentOnErrorCallback',
474
474
  isOptional: true,
475
475
  description: 'Callback invoked when an error occurs during streaming.',
476
476
  },
477
477
  {
478
478
  name: 'onAbort',
479
- type: 'StreamTextOnAbortCallback',
479
+ type: 'WorkflowAgentOnAbortCallback',
480
480
  isOptional: true,
481
481
  description: 'Callback invoked when the operation is aborted. Receives all previously finished steps.',
482
482
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "7.0.0-beta.90",
3
+ "version": "7.0.0-beta.92",
4
4
  "type": "module",
5
5
  "description": "AI SDK by Vercel - build apps like ChatGPT, Claude, Gemini, and more with a single interface for any model using the Vercel AI Gateway or go direct to OpenAI, Anthropic, Google, or any other model provider.",
6
6
  "license": "Apache-2.0",
@@ -42,7 +42,7 @@
42
42
  }
43
43
  },
44
44
  "dependencies": {
45
- "@ai-sdk/gateway": "4.0.0-beta.50",
45
+ "@ai-sdk/gateway": "4.0.0-beta.52",
46
46
  "@ai-sdk/provider": "4.0.0-beta.12",
47
47
  "@ai-sdk/provider-utils": "5.0.0-beta.20"
48
48
  },