@ai-sdk/openai 2.0.140 → 2.0.141

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
@@ -371,10 +371,13 @@ function getResponseMetadata({
371
371
  }
372
372
 
373
373
  // src/chat/map-openai-finish-reason.ts
374
- function mapOpenAIFinishReason(finishReason) {
374
+ function mapOpenAIFinishReason({
375
+ finishReason,
376
+ hasRefusal = false
377
+ }) {
375
378
  switch (finishReason) {
376
379
  case "stop":
377
- return "stop";
380
+ return hasRefusal ? "content-filter" : "stop";
378
381
  case "length":
379
382
  return "length";
380
383
  case "content_filter":
@@ -404,6 +407,8 @@ var openaiChatResponseSchema = lazyValidator(
404
407
  message: z2.object({
405
408
  role: z2.literal("assistant").nullish(),
406
409
  content: z2.string().nullish(),
410
+ // set instead of `content` when the model refuses to answer:
411
+ refusal: z2.string().nullish(),
407
412
  audio: z2.object({
408
413
  transcript: z2.string().nullish()
409
414
  }).nullish(),
@@ -442,6 +447,20 @@ var openaiChatResponseSchema = lazyValidator(
442
447
  })
443
448
  )
444
449
  })
450
+ ).nullish(),
451
+ // logprobs of the refusal tokens (set instead of `content` when
452
+ // the model refuses to answer):
453
+ refusal: z2.array(
454
+ z2.object({
455
+ token: z2.string(),
456
+ logprob: z2.number(),
457
+ top_logprobs: z2.array(
458
+ z2.object({
459
+ token: z2.string(),
460
+ logprob: z2.number()
461
+ })
462
+ )
463
+ })
445
464
  ).nullish()
446
465
  }).nullish(),
447
466
  finish_reason: z2.string().nullish()
@@ -476,6 +495,8 @@ var openaiChatChunkSchema = lazyValidator(
476
495
  delta: z2.object({
477
496
  role: z2.enum(["assistant"]).nullish(),
478
497
  content: z2.string().nullish(),
498
+ // set instead of `content` when the model refuses to answer:
499
+ refusal: z2.string().nullish(),
479
500
  tool_calls: z2.array(
480
501
  z2.object({
481
502
  index: z2.number(),
@@ -511,6 +532,20 @@ var openaiChatChunkSchema = lazyValidator(
511
532
  })
512
533
  )
513
534
  })
535
+ ).nullish(),
536
+ // logprobs of the refusal tokens (set instead of `content` when
537
+ // the model refuses to answer):
538
+ refusal: z2.array(
539
+ z2.object({
540
+ token: z2.string(),
541
+ logprob: z2.number(),
542
+ top_logprobs: z2.array(
543
+ z2.object({
544
+ token: z2.string(),
545
+ logprob: z2.number()
546
+ })
547
+ )
548
+ })
514
549
  ).nullish()
515
550
  }).nullish(),
516
551
  finish_reason: z2.string().nullish(),
@@ -947,7 +982,7 @@ var OpenAIChatLanguageModel = class {
947
982
  };
948
983
  }
949
984
  async doGenerate(options) {
950
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
985
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
951
986
  const { args: body, warnings } = await this.getArgs(options);
952
987
  const {
953
988
  responseHeaders,
@@ -979,6 +1014,11 @@ var OpenAIChatLanguageModel = class {
979
1014
  if (text != null && text.length > 0) {
980
1015
  content.push({ type: "text", text });
981
1016
  }
1017
+ const refusal = choice.message.refusal;
1018
+ const hasRefusal = refusal != null && refusal.length > 0;
1019
+ if (hasRefusal) {
1020
+ content.push({ type: "text", text: refusal });
1021
+ }
982
1022
  for (const toolCall of (_b = choice.message.tool_calls) != null ? _b : []) {
983
1023
  content.push({
984
1024
  type: "tool-call",
@@ -1010,18 +1050,26 @@ var OpenAIChatLanguageModel = class {
1010
1050
  cacheWriteTokens: promptTokenDetails.cache_write_tokens
1011
1051
  };
1012
1052
  }
1013
- if (((_g = choice.logprobs) == null ? void 0 : _g.content) != null) {
1014
- providerMetadata.openai.logprobs = choice.logprobs.content;
1053
+ const contentLogprobs = (_g = choice.logprobs) == null ? void 0 : _g.content;
1054
+ const refusalLogprobs = (_h = choice.logprobs) == null ? void 0 : _h.refusal;
1055
+ if (contentLogprobs != null || refusalLogprobs != null) {
1056
+ providerMetadata.openai.logprobs = [
1057
+ ...contentLogprobs != null ? contentLogprobs : [],
1058
+ ...refusalLogprobs != null ? refusalLogprobs : []
1059
+ ];
1015
1060
  }
1016
1061
  return {
1017
1062
  content,
1018
- finishReason: mapOpenAIFinishReason(choice.finish_reason),
1063
+ finishReason: mapOpenAIFinishReason({
1064
+ finishReason: choice.finish_reason,
1065
+ hasRefusal
1066
+ }),
1019
1067
  usage: {
1020
- inputTokens: (_i = (_h = response.usage) == null ? void 0 : _h.prompt_tokens) != null ? _i : void 0,
1021
- outputTokens: (_k = (_j = response.usage) == null ? void 0 : _j.completion_tokens) != null ? _k : void 0,
1022
- totalTokens: (_m = (_l = response.usage) == null ? void 0 : _l.total_tokens) != null ? _m : void 0,
1023
- reasoningTokens: (_n = completionTokenDetails == null ? void 0 : completionTokenDetails.reasoning_tokens) != null ? _n : void 0,
1024
- cachedInputTokens: (_o = promptTokenDetails == null ? void 0 : promptTokenDetails.cached_tokens) != null ? _o : void 0
1068
+ inputTokens: (_j = (_i = response.usage) == null ? void 0 : _i.prompt_tokens) != null ? _j : void 0,
1069
+ outputTokens: (_l = (_k = response.usage) == null ? void 0 : _k.completion_tokens) != null ? _l : void 0,
1070
+ totalTokens: (_n = (_m = response.usage) == null ? void 0 : _m.total_tokens) != null ? _n : void 0,
1071
+ reasoningTokens: (_o = completionTokenDetails == null ? void 0 : completionTokenDetails.reasoning_tokens) != null ? _o : void 0,
1072
+ cachedInputTokens: (_p = promptTokenDetails == null ? void 0 : promptTokenDetails.cached_tokens) != null ? _p : void 0
1025
1073
  },
1026
1074
  request: { body },
1027
1075
  response: {
@@ -1065,6 +1113,10 @@ var OpenAIChatLanguageModel = class {
1065
1113
  };
1066
1114
  let metadataExtracted = false;
1067
1115
  let isActiveText = false;
1116
+ let hasRefusal = false;
1117
+ let rawFinishReason = void 0;
1118
+ let hasLogprobs = false;
1119
+ const streamedLogprobs = [];
1068
1120
  const providerMetadata = { openai: {} };
1069
1121
  return {
1070
1122
  stream: response.pipeThrough(
@@ -1077,18 +1129,20 @@ var OpenAIChatLanguageModel = class {
1077
1129
  controller.enqueue({ type: "stream-start", warnings });
1078
1130
  },
1079
1131
  transform(chunk, controller) {
1080
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
1132
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
1081
1133
  if (options.includeRawChunks) {
1082
1134
  controller.enqueue({ type: "raw", rawValue: chunk.rawValue });
1083
1135
  }
1084
1136
  if (!chunk.success) {
1085
1137
  finishReason = "error";
1138
+ rawFinishReason = void 0;
1086
1139
  controller.enqueue({ type: "error", error: chunk.error });
1087
1140
  return;
1088
1141
  }
1089
1142
  const value = chunk.value;
1090
1143
  if ("error" in value) {
1091
1144
  finishReason = "error";
1145
+ rawFinishReason = void 0;
1092
1146
  controller.enqueue({ type: "error", error: value.error });
1093
1147
  return;
1094
1148
  }
@@ -1122,16 +1176,35 @@ var OpenAIChatLanguageModel = class {
1122
1176
  }
1123
1177
  const choice = value.choices[0];
1124
1178
  if ((choice == null ? void 0 : choice.finish_reason) != null) {
1125
- finishReason = mapOpenAIFinishReason(choice.finish_reason);
1179
+ rawFinishReason = choice.finish_reason;
1126
1180
  }
1127
- if (((_m = choice == null ? void 0 : choice.logprobs) == null ? void 0 : _m.content) != null) {
1128
- providerMetadata.openai.logprobs = choice.logprobs.content;
1181
+ if ((choice == null ? void 0 : choice.logprobs) != null) {
1182
+ const contentLogprobs = choice.logprobs.content;
1183
+ const refusalLogprobs = choice.logprobs.refusal;
1184
+ if (contentLogprobs != null || refusalLogprobs != null) {
1185
+ hasLogprobs = true;
1186
+ streamedLogprobs.push(
1187
+ ...contentLogprobs != null ? contentLogprobs : [],
1188
+ ...refusalLogprobs != null ? refusalLogprobs : []
1189
+ );
1190
+ }
1129
1191
  }
1130
1192
  if ((choice == null ? void 0 : choice.delta) == null) {
1131
1193
  return;
1132
1194
  }
1133
1195
  const delta = choice.delta;
1134
- if (delta.content != null) {
1196
+ const textDeltas = [];
1197
+ if (delta.content != null && delta.content.length > 0) {
1198
+ textDeltas.push(delta.content);
1199
+ }
1200
+ if (delta.refusal != null && delta.refusal.length > 0) {
1201
+ hasRefusal = true;
1202
+ textDeltas.push(delta.refusal);
1203
+ }
1204
+ if (textDeltas.length === 0 && delta.content === "") {
1205
+ textDeltas.push(delta.content);
1206
+ }
1207
+ for (const textDelta of textDeltas) {
1135
1208
  if (!isActiveText) {
1136
1209
  controller.enqueue({ type: "text-start", id: "0" });
1137
1210
  isActiveText = true;
@@ -1139,7 +1212,7 @@ var OpenAIChatLanguageModel = class {
1139
1212
  controller.enqueue({
1140
1213
  type: "text-delta",
1141
1214
  id: "0",
1142
- delta: delta.content
1215
+ delta: textDelta
1143
1216
  });
1144
1217
  }
1145
1218
  if (delta.tool_calls != null) {
@@ -1164,6 +1237,15 @@ var OpenAIChatLanguageModel = class {
1164
1237
  controller.enqueue({ type: "text-end", id: "0" });
1165
1238
  }
1166
1239
  toolCallTracker.flush();
1240
+ if (rawFinishReason != null) {
1241
+ finishReason = mapOpenAIFinishReason({
1242
+ finishReason: rawFinishReason,
1243
+ hasRefusal
1244
+ });
1245
+ }
1246
+ if (hasLogprobs) {
1247
+ providerMetadata.openai.logprobs = streamedLogprobs;
1248
+ }
1167
1249
  controller.enqueue({
1168
1250
  type: "finish",
1169
1251
  finishReason,
@@ -3077,12 +3159,14 @@ function serializeToolCallArguments2(input) {
3077
3159
  // src/responses/map-openai-responses-finish-reason.ts
3078
3160
  function mapOpenAIResponseFinishReason({
3079
3161
  finishReason,
3080
- hasFunctionCall
3162
+ hasFunctionCall,
3163
+ hasRefusal = false
3081
3164
  }) {
3082
3165
  switch (finishReason) {
3083
3166
  case void 0:
3084
3167
  case null:
3085
- return hasFunctionCall ? "tool-calls" : "stop";
3168
+ if (hasFunctionCall) return "tool-calls";
3169
+ return hasRefusal ? "content-filter" : "stop";
3086
3170
  case "max_output_tokens":
3087
3171
  return "length";
3088
3172
  case "content_filter":
@@ -3118,6 +3202,20 @@ var openaiResponsesChunkSchema = lazyValidator10(
3118
3202
  })
3119
3203
  ).nullish()
3120
3204
  }),
3205
+ z18.object({
3206
+ type: z18.literal("response.refusal.delta"),
3207
+ item_id: z18.string(),
3208
+ output_index: z18.number().nullish(),
3209
+ content_index: z18.number().nullish(),
3210
+ delta: z18.string()
3211
+ }),
3212
+ z18.object({
3213
+ type: z18.literal("response.refusal.done"),
3214
+ item_id: z18.string(),
3215
+ output_index: z18.number().nullish(),
3216
+ content_index: z18.number().nullish(),
3217
+ refusal: z18.string()
3218
+ }),
3121
3219
  z18.object({
3122
3220
  type: z18.enum(["response.completed", "response.incomplete"]),
3123
3221
  response: z18.object({
@@ -3404,57 +3502,64 @@ var openaiResponsesResponseSchema = lazyValidator10(
3404
3502
  role: z18.literal("assistant"),
3405
3503
  id: z18.string(),
3406
3504
  phase: z18.enum(["commentary", "final_answer"]).nullish(),
3505
+ // the API returns either text or a refusal as content parts:
3407
3506
  content: z18.array(
3408
- z18.object({
3409
- type: z18.literal("output_text"),
3410
- text: z18.string(),
3411
- logprobs: z18.array(
3412
- z18.object({
3413
- token: z18.string(),
3414
- logprob: z18.number(),
3415
- top_logprobs: z18.array(
3416
- z18.object({
3417
- token: z18.string(),
3418
- logprob: z18.number()
3419
- })
3420
- )
3421
- })
3422
- ).nullish(),
3423
- annotations: z18.array(
3424
- z18.discriminatedUnion("type", [
3425
- z18.object({
3426
- type: z18.literal("url_citation"),
3427
- start_index: z18.number(),
3428
- end_index: z18.number(),
3429
- url: z18.string(),
3430
- title: z18.string()
3431
- }),
3432
- z18.object({
3433
- type: z18.literal("file_citation"),
3434
- file_id: z18.string(),
3435
- filename: z18.string().nullish(),
3436
- index: z18.number().nullish(),
3437
- start_index: z18.number().nullish(),
3438
- end_index: z18.number().nullish(),
3439
- quote: z18.string().nullish()
3440
- }),
3441
- z18.object({
3442
- type: z18.literal("container_file_citation"),
3443
- container_id: z18.string(),
3444
- file_id: z18.string(),
3445
- filename: z18.string().nullish(),
3446
- start_index: z18.number().nullish(),
3447
- end_index: z18.number().nullish(),
3448
- index: z18.number().nullish()
3449
- }),
3507
+ z18.discriminatedUnion("type", [
3508
+ z18.object({
3509
+ type: z18.literal("output_text"),
3510
+ text: z18.string(),
3511
+ logprobs: z18.array(
3450
3512
  z18.object({
3451
- type: z18.literal("file_path"),
3452
- file_id: z18.string(),
3453
- index: z18.number().nullish()
3513
+ token: z18.string(),
3514
+ logprob: z18.number(),
3515
+ top_logprobs: z18.array(
3516
+ z18.object({
3517
+ token: z18.string(),
3518
+ logprob: z18.number()
3519
+ })
3520
+ )
3454
3521
  })
3455
- ])
3456
- )
3457
- })
3522
+ ).nullish(),
3523
+ annotations: z18.array(
3524
+ z18.discriminatedUnion("type", [
3525
+ z18.object({
3526
+ type: z18.literal("url_citation"),
3527
+ start_index: z18.number(),
3528
+ end_index: z18.number(),
3529
+ url: z18.string(),
3530
+ title: z18.string()
3531
+ }),
3532
+ z18.object({
3533
+ type: z18.literal("file_citation"),
3534
+ file_id: z18.string(),
3535
+ filename: z18.string().nullish(),
3536
+ index: z18.number().nullish(),
3537
+ start_index: z18.number().nullish(),
3538
+ end_index: z18.number().nullish(),
3539
+ quote: z18.string().nullish()
3540
+ }),
3541
+ z18.object({
3542
+ type: z18.literal("container_file_citation"),
3543
+ container_id: z18.string(),
3544
+ file_id: z18.string(),
3545
+ filename: z18.string().nullish(),
3546
+ start_index: z18.number().nullish(),
3547
+ end_index: z18.number().nullish(),
3548
+ index: z18.number().nullish()
3549
+ }),
3550
+ z18.object({
3551
+ type: z18.literal("file_path"),
3552
+ file_id: z18.string(),
3553
+ index: z18.number().nullish()
3554
+ })
3555
+ ])
3556
+ )
3557
+ }),
3558
+ z18.object({
3559
+ type: z18.literal("refusal"),
3560
+ refusal: z18.string()
3561
+ })
3562
+ ])
3458
3563
  )
3459
3564
  }),
3460
3565
  z18.object({
@@ -4118,6 +4223,7 @@ var OpenAIResponsesLanguageModel = class {
4118
4223
  const content = [];
4119
4224
  const logprobs = [];
4120
4225
  let hasFunctionCall = false;
4226
+ let hasRefusal = false;
4121
4227
  for (const part of response.output) {
4122
4228
  switch (part.type) {
4123
4229
  case "reasoning": {
@@ -4175,6 +4281,20 @@ var OpenAIResponsesLanguageModel = class {
4175
4281
  }
4176
4282
  case "message": {
4177
4283
  for (const contentPart of part.content) {
4284
+ if (contentPart.type === "refusal") {
4285
+ hasRefusal = true;
4286
+ content.push({
4287
+ type: "text",
4288
+ text: contentPart.refusal,
4289
+ providerMetadata: {
4290
+ [providerKey]: {
4291
+ itemId: part.id,
4292
+ ...part.phase != null && { phase: part.phase }
4293
+ }
4294
+ }
4295
+ });
4296
+ continue;
4297
+ }
4178
4298
  if (((_c = (_b = options.providerOptions) == null ? void 0 : _b.openai) == null ? void 0 : _c.logprobs) && contentPart.logprobs) {
4179
4299
  logprobs.push(contentPart.logprobs);
4180
4300
  }
@@ -4375,7 +4495,8 @@ var OpenAIResponsesLanguageModel = class {
4375
4495
  content,
4376
4496
  finishReason: mapOpenAIResponseFinishReason({
4377
4497
  finishReason: (_y = response.incomplete_details) == null ? void 0 : _y.reason,
4378
- hasFunctionCall
4498
+ hasFunctionCall,
4499
+ hasRefusal
4379
4500
  }),
4380
4501
  usage: {
4381
4502
  inputTokens: usage.input_tokens,
@@ -4434,6 +4555,7 @@ var OpenAIResponsesLanguageModel = class {
4434
4555
  const ongoingAnnotations = [];
4435
4556
  let activeMessagePhase;
4436
4557
  let hasFunctionCall = false;
4558
+ let hasRefusal = false;
4437
4559
  const activeReasoning = {};
4438
4560
  let serviceTier;
4439
4561
  let reasoningContext;
@@ -4775,6 +4897,15 @@ var OpenAIResponsesLanguageModel = class {
4775
4897
  if (((_h = (_g = options.providerOptions) == null ? void 0 : _g.openai) == null ? void 0 : _h.logprobs) && value.logprobs) {
4776
4898
  logprobs.push(value.logprobs);
4777
4899
  }
4900
+ } else if (isRefusalDeltaChunk(value)) {
4901
+ hasRefusal = true;
4902
+ controller.enqueue({
4903
+ type: "text-delta",
4904
+ id: value.item_id,
4905
+ delta: value.delta
4906
+ });
4907
+ } else if (isRefusalDoneChunk(value)) {
4908
+ hasRefusal = true;
4778
4909
  } else if (value.type === "response.reasoning_summary_part.added") {
4779
4910
  if (value.summary_index > 0) {
4780
4911
  const activeReasoningPart = activeReasoning[value.item_id];
@@ -4831,7 +4962,8 @@ var OpenAIResponsesLanguageModel = class {
4831
4962
  } else if (isResponseFinishedChunk(value)) {
4832
4963
  finishReason = mapOpenAIResponseFinishReason({
4833
4964
  finishReason: (_k = value.response.incomplete_details) == null ? void 0 : _k.reason,
4834
- hasFunctionCall
4965
+ hasFunctionCall,
4966
+ hasRefusal
4835
4967
  });
4836
4968
  usage.inputTokens = value.response.usage.input_tokens;
4837
4969
  usage.outputTokens = value.response.usage.output_tokens;
@@ -4908,6 +5040,12 @@ var OpenAIResponsesLanguageModel = class {
4908
5040
  };
4909
5041
  }
4910
5042
  };
5043
+ function isRefusalDeltaChunk(chunk) {
5044
+ return chunk.type === "response.refusal.delta";
5045
+ }
5046
+ function isRefusalDoneChunk(chunk) {
5047
+ return chunk.type === "response.refusal.done";
5048
+ }
4911
5049
  function isTextDeltaChunk(chunk) {
4912
5050
  return chunk.type === "response.output_text.delta";
4913
5051
  }
@@ -5376,7 +5514,7 @@ var OpenAITranscriptionModel = class {
5376
5514
  };
5377
5515
 
5378
5516
  // src/version.ts
5379
- var VERSION = true ? "2.0.140" : "0.0.0-test";
5517
+ var VERSION = true ? "2.0.141" : "0.0.0-test";
5380
5518
 
5381
5519
  // src/openai-provider.ts
5382
5520
  function createOpenAI(options = {}) {