@ai-sdk/openai 3.0.109 → 3.0.111

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.js CHANGED
@@ -69,6 +69,7 @@ function getOpenAILanguageModelCapabilities(modelId) {
69
69
  supportsFlexProcessing,
70
70
  supportsPriorityProcessing,
71
71
  supportsConfigurationUpdate: isGpt6OrLaterModel,
72
+ supportsAsyncToolCalling: isGpt6OrLaterModel,
72
73
  supportedReasoningEfforts: isGpt6OrLaterModel ? ["low", "medium", "high", "xhigh", "max"] : void 0,
73
74
  isReasoningModel,
74
75
  systemMessageMode,
@@ -2056,6 +2057,10 @@ var modelMaxImagesPerCall = {
2056
2057
  "gpt-image-1-mini": 10,
2057
2058
  "gpt-image-1.5": 10,
2058
2059
  "gpt-image-2": 10,
2060
+ "gpt-image-2.5-flare": 10,
2061
+ "gpt-image-2.5-flare-2026-09-08": 10,
2062
+ "gpt-image-2.5-sunburst": 10,
2063
+ "gpt-image-2.5-sunburst-2026-09-08": 10,
2059
2064
  "chatgpt-image-latest": 10
2060
2065
  };
2061
2066
  var defaultResponseFormatPrefixes = ["chatgpt-image-", "gpt-image-"];
@@ -2072,9 +2077,10 @@ var baseImageModelOptionsObject = import_v49.z.object({
2072
2077
  /**
2073
2078
  * Quality of the generated image(s).
2074
2079
  *
2075
- * Valid values: `standard`, `hd`, `low`, `medium`, `high`, `auto`.
2080
+ * Valid values: `standard`, `hd`, `low`, `medium`, `high`, `xhigh`, `max`, `auto`.
2081
+ * `xhigh` and `max` are supported by GPT Image 2.5 models.
2076
2082
  */
2077
- quality: import_v49.z.enum(["standard", "hd", "low", "medium", "high", "auto"]).optional(),
2083
+ quality: import_v49.z.enum(["standard", "hd", "low", "medium", "high", "xhigh", "max", "auto"]).optional(),
2078
2084
  /**
2079
2085
  * Background behavior for the generated image(s).
2080
2086
  *
@@ -2435,6 +2441,7 @@ var customArgsSchema = (0, import_provider_utils17.lazySchema)(
2435
2441
  import_v412.z.object({
2436
2442
  name: import_v412.z.string(),
2437
2443
  description: import_v412.z.string().optional(),
2444
+ async: import_v412.z.boolean().optional(),
2438
2445
  format: import_v412.z.union([
2439
2446
  import_v412.z.object({
2440
2447
  type: import_v412.z.literal("grammar"),
@@ -2521,7 +2528,7 @@ var imageGenerationArgsSchema = (0, import_provider_utils19.lazySchema)(
2521
2528
  outputCompression: import_v414.z.number().int().min(0).max(100).optional(),
2522
2529
  outputFormat: import_v414.z.enum(["png", "jpeg", "webp"]).optional(),
2523
2530
  partialImages: import_v414.z.number().int().min(0).max(3).optional(),
2524
- quality: import_v414.z.enum(["auto", "low", "medium", "high"]).optional(),
2531
+ quality: import_v414.z.enum(["auto", "low", "medium", "high", "xhigh", "max"]).optional(),
2525
2532
  size: import_v414.z.enum(["1024x1024", "1024x1536", "1536x1024", "auto"]).optional()
2526
2533
  }).strict()
2527
2534
  )
@@ -2881,6 +2888,7 @@ var openaiTools = {
2881
2888
  *
2882
2889
  * @param name - The name of the custom tool.
2883
2890
  * @param description - An optional description of the tool.
2891
+ * @param async - Whether the model can continue without waiting for the tool result.
2884
2892
  * @param format - The output format constraint (grammar type, syntax, and definition).
2885
2893
  */
2886
2894
  customTool,
@@ -2916,7 +2924,7 @@ var openaiTools = {
2916
2924
  * @param outputCompression - Compression level for the output image (0-100).
2917
2925
  * @param outputFormat - The output format of the generated image. One of 'png', 'jpeg', or 'webp'.
2918
2926
  * @param partialImages - Number of partial images to generate in streaming mode (0-3).
2919
- * @param quality - The quality of the generated image. One of 'auto', 'low', 'medium', or 'high'.
2927
+ * @param quality - The quality of the generated image. One of 'auto', 'low', 'medium', 'high', 'xhigh', or 'max'. 'xhigh' and 'max' require a GPT Image 2.5 model.
2920
2928
  * @param size - The size of the generated image. One of 'auto', '1024x1024', '1024x1536', or '1536x1024'.
2921
2929
  */
2922
2930
  imageGeneration,
@@ -3285,6 +3293,7 @@ async function convertToOpenAIResponsesInput({
3285
3293
  toolNameMapping,
3286
3294
  systemMessageMode,
3287
3295
  providerOptionsName,
3296
+ explicitMessageItemType = false,
3288
3297
  fileIdPrefixes,
3289
3298
  passThroughUnsupportedFiles = false,
3290
3299
  store,
@@ -3296,7 +3305,7 @@ async function convertToOpenAIResponsesInput({
3296
3305
  toolSearchToolName,
3297
3306
  customProviderToolNames
3298
3307
  }) {
3299
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
3308
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D;
3300
3309
  let input = [];
3301
3310
  const warnings = [];
3302
3311
  const processedApprovalIds = /* @__PURE__ */ new Set();
@@ -3316,6 +3325,7 @@ async function convertToOpenAIResponsesInput({
3316
3325
  providerOptionsName
3317
3326
  );
3318
3327
  input.push({
3328
+ ...explicitMessageItemType && { type: "message" },
3319
3329
  role: "system",
3320
3330
  content: promptCacheBreakpoint == null ? content : [
3321
3331
  {
@@ -3333,6 +3343,7 @@ async function convertToOpenAIResponsesInput({
3333
3343
  providerOptionsName
3334
3344
  );
3335
3345
  input.push({
3346
+ ...explicitMessageItemType && { type: "message" },
3336
3347
  role: "developer",
3337
3348
  content: promptCacheBreakpoint == null ? content : [
3338
3349
  {
@@ -3362,6 +3373,7 @@ async function convertToOpenAIResponsesInput({
3362
3373
  }
3363
3374
  case "user": {
3364
3375
  input.push({
3376
+ ...explicitMessageItemType && { type: "message" },
3365
3377
  role: "user",
3366
3378
  content: content.map((part, index) => {
3367
3379
  var _a3, _b2, _c2;
@@ -3443,6 +3455,7 @@ async function convertToOpenAIResponsesInput({
3443
3455
  break;
3444
3456
  }
3445
3457
  input.push({
3458
+ ...explicitMessageItemType && { type: "message" },
3446
3459
  role: "assistant",
3447
3460
  content: [{ type: "output_text", text: part.text }],
3448
3461
  id,
@@ -3481,6 +3494,7 @@ async function convertToOpenAIResponsesInput({
3481
3494
  }
3482
3495
  const id = (_f = (_c = (_b = part.providerOptions) == null ? void 0 : _b[providerOptionsName]) == null ? void 0 : _c.itemId) != null ? _f : (_e = (_d = part.providerMetadata) == null ? void 0 : _d[providerOptionsName]) == null ? void 0 : _e.itemId;
3483
3496
  const namespace = (_k = (_h = (_g = part.providerOptions) == null ? void 0 : _g[providerOptionsName]) == null ? void 0 : _h.namespace) != null ? _k : (_j = (_i = part.providerMetadata) == null ? void 0 : _i[providerOptionsName]) == null ? void 0 : _j.namespace;
3497
+ const isAsync = (_p = (_m = (_l = part.providerOptions) == null ? void 0 : _l[providerOptionsName]) == null ? void 0 : _m.async) != null ? _p : (_o = (_n = part.providerMetadata) == null ? void 0 : _n[providerOptionsName]) == null ? void 0 : _o.async;
3484
3498
  if (hasConversation && id != null) {
3485
3499
  break;
3486
3500
  }
@@ -3504,7 +3518,7 @@ async function convertToOpenAIResponsesInput({
3504
3518
  type: "tool_search_call",
3505
3519
  id: id != null ? id : part.toolCallId,
3506
3520
  execution,
3507
- call_id: (_l = parsedInput.call_id) != null ? _l : null,
3521
+ call_id: (_q = parsedInput.call_id) != null ? _q : null,
3508
3522
  status: "completed",
3509
3523
  arguments: parsedInput.arguments
3510
3524
  });
@@ -3518,7 +3532,7 @@ async function convertToOpenAIResponsesInput({
3518
3532
  break;
3519
3533
  }
3520
3534
  }
3521
- const isProviderDefinedToolCall = hasLocalShellTool && resolvedToolName === "local_shell" || hasShellTool && resolvedToolName === "shell" || hasApplyPatchTool && resolvedToolName === "apply_patch" || ((_m = customProviderToolNames == null ? void 0 : customProviderToolNames.has(resolvedToolName)) != null ? _m : false);
3535
+ const isProviderDefinedToolCall = hasLocalShellTool && resolvedToolName === "local_shell" || hasShellTool && resolvedToolName === "shell" || hasApplyPatchTool && resolvedToolName === "apply_patch" || ((_r = customProviderToolNames == null ? void 0 : customProviderToolNames.has(resolvedToolName)) != null ? _r : false);
3522
3536
  if (hasPreviousResponseId && store && id != null && isProviderDefinedToolCall) {
3523
3537
  break;
3524
3538
  }
@@ -3584,6 +3598,7 @@ async function convertToOpenAIResponsesInput({
3584
3598
  call_id: part.toolCallId,
3585
3599
  name: resolvedToolName,
3586
3600
  input: typeof part.input === "string" ? part.input : JSON.stringify(part.input),
3601
+ ...isAsync != null && { async: isAsync },
3587
3602
  id
3588
3603
  });
3589
3604
  break;
@@ -3593,6 +3608,7 @@ async function convertToOpenAIResponsesInput({
3593
3608
  call_id: part.toolCallId,
3594
3609
  name: resolvedToolName,
3595
3610
  arguments: serializeToolCallArguments2(part.input),
3611
+ ...isAsync != null && { async: isAsync },
3596
3612
  ...namespace != null && { namespace }
3597
3613
  });
3598
3614
  break;
@@ -3609,7 +3625,7 @@ async function convertToOpenAIResponsesInput({
3609
3625
  part.toolName
3610
3626
  );
3611
3627
  if (part.toolName === toolSearchToolName) {
3612
- const itemId = (_s = (_r = (_o = (_n = part.providerOptions) == null ? void 0 : _n[providerOptionsName]) == null ? void 0 : _o.itemId) != null ? _r : (_q = (_p = part.providerMetadata) == null ? void 0 : _p[providerOptionsName]) == null ? void 0 : _q.itemId) != null ? _s : part.toolCallId;
3628
+ const itemId = (_x = (_w = (_t = (_s = part.providerOptions) == null ? void 0 : _s[providerOptionsName]) == null ? void 0 : _t.itemId) != null ? _w : (_v = (_u = part.providerMetadata) == null ? void 0 : _u[providerOptionsName]) == null ? void 0 : _v.itemId) != null ? _x : part.toolCallId;
3613
3629
  if (store) {
3614
3630
  input.push({ type: "item_reference", id: itemId });
3615
3631
  } else if (part.output.type === "json") {
@@ -3650,7 +3666,7 @@ async function convertToOpenAIResponsesInput({
3650
3666
  break;
3651
3667
  }
3652
3668
  if (store) {
3653
- const itemId = (_v = (_u = (_t = part.providerOptions) == null ? void 0 : _t[providerOptionsName]) == null ? void 0 : _u.itemId) != null ? _v : part.toolCallId;
3669
+ const itemId = (_A = (_z = (_y = part.providerOptions) == null ? void 0 : _y[providerOptionsName]) == null ? void 0 : _z.itemId) != null ? _A : part.toolCallId;
3654
3670
  input.push({ type: "item_reference", id: itemId });
3655
3671
  } else {
3656
3672
  warnings.push({
@@ -3817,7 +3833,7 @@ ${text}`,
3817
3833
  }
3818
3834
  const output = part.output;
3819
3835
  if (output.type === "execution-denied") {
3820
- const approvalId = (_x = (_w = output.providerOptions) == null ? void 0 : _w.openai) == null ? void 0 : _x.approvalId;
3836
+ const approvalId = (_C = (_B = output.providerOptions) == null ? void 0 : _B.openai) == null ? void 0 : _C.approvalId;
3821
3837
  if (approvalId) {
3822
3838
  continue;
3823
3839
  }
@@ -3904,7 +3920,7 @@ ${text}`,
3904
3920
  break;
3905
3921
  case "execution-denied":
3906
3922
  outputValue = convertScalarOutput(
3907
- (_y = output.reason) != null ? _y : "Tool call execution denied."
3923
+ (_D = output.reason) != null ? _D : "Tool call execution denied."
3908
3924
  );
3909
3925
  break;
3910
3926
  case "json":
@@ -4242,6 +4258,7 @@ var openaiResponsesChunkSchema = (0, import_provider_utils28.lazySchema)(
4242
4258
  call_id: import_v422.z.string(),
4243
4259
  name: import_v422.z.string(),
4244
4260
  arguments: import_v422.z.string(),
4261
+ async: import_v422.z.boolean().nullish(),
4245
4262
  namespace: import_v422.z.string().nullish()
4246
4263
  }),
4247
4264
  import_v422.z.object({
@@ -4317,7 +4334,8 @@ var openaiResponsesChunkSchema = (0, import_provider_utils28.lazySchema)(
4317
4334
  id: import_v422.z.string(),
4318
4335
  call_id: import_v422.z.string(),
4319
4336
  name: import_v422.z.string(),
4320
- input: import_v422.z.string()
4337
+ input: import_v422.z.string(),
4338
+ async: import_v422.z.boolean().nullish()
4321
4339
  }),
4322
4340
  import_v422.z.object({
4323
4341
  type: import_v422.z.literal("shell_call"),
@@ -4385,6 +4403,7 @@ var openaiResponsesChunkSchema = (0, import_provider_utils28.lazySchema)(
4385
4403
  call_id: import_v422.z.string(),
4386
4404
  name: import_v422.z.string(),
4387
4405
  arguments: import_v422.z.string(),
4406
+ async: import_v422.z.boolean().nullish(),
4388
4407
  status: import_v422.z.literal("completed"),
4389
4408
  namespace: import_v422.z.string().nullish()
4390
4409
  }),
@@ -4394,6 +4413,7 @@ var openaiResponsesChunkSchema = (0, import_provider_utils28.lazySchema)(
4394
4413
  call_id: import_v422.z.string(),
4395
4414
  name: import_v422.z.string(),
4396
4415
  input: import_v422.z.string(),
4416
+ async: import_v422.z.boolean().nullish(),
4397
4417
  status: import_v422.z.literal("completed")
4398
4418
  }),
4399
4419
  import_v422.z.object({
@@ -4827,6 +4847,7 @@ var openaiResponsesResponseSchema = (0, import_provider_utils28.lazySchema)(
4827
4847
  name: import_v422.z.string(),
4828
4848
  arguments: import_v422.z.string(),
4829
4849
  id: import_v422.z.string(),
4850
+ async: import_v422.z.boolean().nullish(),
4830
4851
  namespace: import_v422.z.string().nullish()
4831
4852
  }),
4832
4853
  import_v422.z.object({
@@ -4834,7 +4855,8 @@ var openaiResponsesResponseSchema = (0, import_provider_utils28.lazySchema)(
4834
4855
  call_id: import_v422.z.string(),
4835
4856
  name: import_v422.z.string(),
4836
4857
  input: import_v422.z.string(),
4837
- id: import_v422.z.string()
4858
+ id: import_v422.z.string(),
4859
+ async: import_v422.z.boolean().nullish()
4838
4860
  }),
4839
4861
  import_v422.z.object({
4840
4862
  type: import_v422.z.literal("computer_call"),
@@ -5266,7 +5288,8 @@ async function prepareResponsesTools({
5266
5288
  toolChoice,
5267
5289
  allowedTools,
5268
5290
  toolNameMapping,
5269
- customProviderToolNames
5291
+ customProviderToolNames,
5292
+ supportsAsyncToolCalling = true
5270
5293
  }) {
5271
5294
  var _a2, _b, _c, _d;
5272
5295
  tools = (tools == null ? void 0 : tools.length) ? tools : void 0;
@@ -5297,7 +5320,13 @@ async function prepareResponsesTools({
5297
5320
  const openaiOptions = (_a2 = tool.providerOptions) == null ? void 0 : _a2.openai;
5298
5321
  const openaiFunctionTool = prepareFunctionTool({
5299
5322
  tool,
5300
- options: openaiOptions
5323
+ options: openaiOptions,
5324
+ async: resolveAsyncToolOption({
5325
+ value: openaiOptions == null ? void 0 : openaiOptions.async,
5326
+ supportsAsyncToolCalling,
5327
+ toolName: tool.name,
5328
+ toolWarnings
5329
+ })
5301
5330
  });
5302
5331
  const namespace = openaiOptions == null ? void 0 : openaiOptions.namespace;
5303
5332
  if (namespace == null) {
@@ -5479,6 +5508,12 @@ async function prepareResponsesTools({
5479
5508
  type: "custom",
5480
5509
  name: args.name,
5481
5510
  description: args.description,
5511
+ ...resolveAsyncToolOption({
5512
+ value: args.async,
5513
+ supportsAsyncToolCalling,
5514
+ toolName: args.name,
5515
+ toolWarnings
5516
+ }) != null ? { async: args.async } : {},
5482
5517
  format: args.format
5483
5518
  });
5484
5519
  resolvedCustomProviderToolNames.add(args.name);
@@ -5650,7 +5685,8 @@ function toAllowedToolResolution(tool) {
5650
5685
  }
5651
5686
  function prepareFunctionTool({
5652
5687
  tool,
5653
- options
5688
+ options,
5689
+ async
5654
5690
  }) {
5655
5691
  const deferLoading = options == null ? void 0 : options.deferLoading;
5656
5692
  return {
@@ -5658,10 +5694,27 @@ function prepareFunctionTool({
5658
5694
  name: tool.name,
5659
5695
  description: tool.description,
5660
5696
  parameters: tool.inputSchema,
5697
+ ...async != null ? { async } : {},
5661
5698
  ...tool.strict != null ? { strict: tool.strict } : {},
5662
5699
  ...deferLoading != null ? { defer_loading: deferLoading } : {}
5663
5700
  };
5664
5701
  }
5702
+ function resolveAsyncToolOption({
5703
+ value,
5704
+ supportsAsyncToolCalling,
5705
+ toolName,
5706
+ toolWarnings
5707
+ }) {
5708
+ if (value !== true || supportsAsyncToolCalling) {
5709
+ return value;
5710
+ }
5711
+ toolWarnings.push({
5712
+ type: "unsupported",
5713
+ feature: `async tool calling for "${toolName}"`,
5714
+ details: "Async tool calling is only supported by GPT-6 and later models."
5715
+ });
5716
+ return void 0;
5717
+ }
5665
5718
  function mapShellEnvironment(environment) {
5666
5719
  if (environment.type === "containerReference") {
5667
5720
  const env2 = environment;
@@ -5829,13 +5882,15 @@ var OpenAIResponsesLanguageModel = class {
5829
5882
  toolChoice,
5830
5883
  allowedTools: (_b = openaiOptions == null ? void 0 : openaiOptions.allowedTools) != null ? _b : void 0,
5831
5884
  toolNameMapping,
5832
- customProviderToolNames
5885
+ customProviderToolNames,
5886
+ supportsAsyncToolCalling: modelCapabilities.supportsAsyncToolCalling
5833
5887
  });
5834
5888
  const { input, warnings: inputWarnings } = await convertToOpenAIResponsesInput({
5835
5889
  prompt,
5836
5890
  toolNameMapping,
5837
5891
  systemMessageMode: (_c = openaiOptions == null ? void 0 : openaiOptions.systemMessageMode) != null ? _c : isReasoningModel ? "developer" : modelCapabilities.systemMessageMode,
5838
5892
  providerOptionsName,
5893
+ explicitMessageItemType: this.config.explicitMessageItemType,
5839
5894
  fileIdPrefixes: this.config.fileIdPrefixes,
5840
5895
  passThroughUnsupportedFiles: (_d = openaiOptions == null ? void 0 : openaiOptions.passThroughUnsupportedFiles) != null ? _d : false,
5841
5896
  store: (_e = openaiOptions == null ? void 0 : openaiOptions.store) != null ? _e : true,
@@ -6339,6 +6394,7 @@ var OpenAIResponsesLanguageModel = class {
6339
6394
  providerMetadata: {
6340
6395
  [providerOptionsName]: {
6341
6396
  itemId: part.id,
6397
+ ...part.async != null && { async: part.async },
6342
6398
  ...part.namespace != null && { namespace: part.namespace }
6343
6399
  }
6344
6400
  }
@@ -6355,7 +6411,8 @@ var OpenAIResponsesLanguageModel = class {
6355
6411
  input: JSON.stringify(part.input),
6356
6412
  providerMetadata: {
6357
6413
  [providerOptionsName]: {
6358
- itemId: part.id
6414
+ itemId: part.id,
6415
+ ...part.async != null && { async: part.async }
6359
6416
  }
6360
6417
  }
6361
6418
  });
@@ -6643,7 +6700,8 @@ var OpenAIResponsesLanguageModel = class {
6643
6700
  toolName: value.item.name,
6644
6701
  toolCallId: value.item.call_id,
6645
6702
  suppressInputStreaming,
6646
- bufferedInputDeltas: suppressInputStreaming ? [] : void 0
6703
+ bufferedInputDeltas: suppressInputStreaming ? [] : void 0,
6704
+ async: value.item.async
6647
6705
  };
6648
6706
  if (!suppressInputStreaming) {
6649
6707
  controller.enqueue({
@@ -6658,7 +6716,8 @@ var OpenAIResponsesLanguageModel = class {
6658
6716
  );
6659
6717
  ongoingToolCalls[value.output_index] = {
6660
6718
  toolName,
6661
- toolCallId: value.item.call_id
6719
+ toolCallId: value.item.call_id,
6720
+ async: value.item.async
6662
6721
  };
6663
6722
  controller.enqueue({
6664
6723
  type: "tool-input-start",
@@ -6902,6 +6961,7 @@ var OpenAIResponsesLanguageModel = class {
6902
6961
  providerMetadata: {
6903
6962
  [providerOptionsName]: {
6904
6963
  itemId: item.id,
6964
+ ...item.async != null ? { async: item.async } : (ongoingToolCall == null ? void 0 : ongoingToolCall.async) != null ? { async: ongoingToolCall.async } : {},
6905
6965
  ...item.namespace != null && {
6906
6966
  namespace: item.namespace
6907
6967
  }
@@ -6946,6 +7006,7 @@ var OpenAIResponsesLanguageModel = class {
6946
7006
  }
6947
7007
  });
6948
7008
  } else if (value.item.type === "custom_tool_call") {
7009
+ const ongoingToolCall = ongoingToolCalls[value.output_index];
6949
7010
  ongoingToolCalls[value.output_index] = void 0;
6950
7011
  hasFunctionCall = true;
6951
7012
  const toolName = toolNameMapping.toCustomToolName(
@@ -6962,7 +7023,8 @@ var OpenAIResponsesLanguageModel = class {
6962
7023
  input: JSON.stringify(value.item.input),
6963
7024
  providerMetadata: {
6964
7025
  [providerOptionsName]: {
6965
- itemId: value.item.id
7026
+ itemId: value.item.id,
7027
+ ...value.item.async != null ? { async: value.item.async } : (ongoingToolCall == null ? void 0 : ongoingToolCall.async) != null ? { async: ongoingToolCall.async } : {}
6966
7028
  }
6967
7029
  }
6968
7030
  });
@@ -8040,7 +8102,7 @@ var OpenAITranscriptionModel = class {
8040
8102
  };
8041
8103
 
8042
8104
  // src/version.ts
8043
- var VERSION = true ? "3.0.109" : "0.0.0-test";
8105
+ var VERSION = true ? "3.0.111" : "0.0.0-test";
8044
8106
 
8045
8107
  // src/openai-provider.ts
8046
8108
  function createOpenAI(options = {}) {