@ai-sdk/openai 2.0.140 → 2.0.142

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.
@@ -403,10 +403,13 @@ function getResponseMetadata({
403
403
  }
404
404
 
405
405
  // src/chat/map-openai-finish-reason.ts
406
- function mapOpenAIFinishReason(finishReason) {
406
+ function mapOpenAIFinishReason({
407
+ finishReason,
408
+ hasRefusal = false
409
+ }) {
407
410
  switch (finishReason) {
408
411
  case "stop":
409
- return "stop";
412
+ return hasRefusal ? "content-filter" : "stop";
410
413
  case "length":
411
414
  return "length";
412
415
  case "content_filter":
@@ -433,6 +436,8 @@ var openaiChatResponseSchema = (0, import_provider_utils3.lazyValidator)(
433
436
  message: import_v42.z.object({
434
437
  role: import_v42.z.literal("assistant").nullish(),
435
438
  content: import_v42.z.string().nullish(),
439
+ // set instead of `content` when the model refuses to answer:
440
+ refusal: import_v42.z.string().nullish(),
436
441
  audio: import_v42.z.object({
437
442
  transcript: import_v42.z.string().nullish()
438
443
  }).nullish(),
@@ -471,6 +476,20 @@ var openaiChatResponseSchema = (0, import_provider_utils3.lazyValidator)(
471
476
  })
472
477
  )
473
478
  })
479
+ ).nullish(),
480
+ // logprobs of the refusal tokens (set instead of `content` when
481
+ // the model refuses to answer):
482
+ refusal: import_v42.z.array(
483
+ import_v42.z.object({
484
+ token: import_v42.z.string(),
485
+ logprob: import_v42.z.number(),
486
+ top_logprobs: import_v42.z.array(
487
+ import_v42.z.object({
488
+ token: import_v42.z.string(),
489
+ logprob: import_v42.z.number()
490
+ })
491
+ )
492
+ })
474
493
  ).nullish()
475
494
  }).nullish(),
476
495
  finish_reason: import_v42.z.string().nullish()
@@ -505,6 +524,8 @@ var openaiChatChunkSchema = (0, import_provider_utils3.lazyValidator)(
505
524
  delta: import_v42.z.object({
506
525
  role: import_v42.z.enum(["assistant"]).nullish(),
507
526
  content: import_v42.z.string().nullish(),
527
+ // set instead of `content` when the model refuses to answer:
528
+ refusal: import_v42.z.string().nullish(),
508
529
  tool_calls: import_v42.z.array(
509
530
  import_v42.z.object({
510
531
  index: import_v42.z.number(),
@@ -540,6 +561,20 @@ var openaiChatChunkSchema = (0, import_provider_utils3.lazyValidator)(
540
561
  })
541
562
  )
542
563
  })
564
+ ).nullish(),
565
+ // logprobs of the refusal tokens (set instead of `content` when
566
+ // the model refuses to answer):
567
+ refusal: import_v42.z.array(
568
+ import_v42.z.object({
569
+ token: import_v42.z.string(),
570
+ logprob: import_v42.z.number(),
571
+ top_logprobs: import_v42.z.array(
572
+ import_v42.z.object({
573
+ token: import_v42.z.string(),
574
+ logprob: import_v42.z.number()
575
+ })
576
+ )
577
+ })
543
578
  ).nullish()
544
579
  }).nullish(),
545
580
  finish_reason: import_v42.z.string().nullish(),
@@ -971,7 +1006,7 @@ var OpenAIChatLanguageModel = class {
971
1006
  };
972
1007
  }
973
1008
  async doGenerate(options) {
974
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
1009
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
975
1010
  const { args: body, warnings } = await this.getArgs(options);
976
1011
  const {
977
1012
  responseHeaders,
@@ -1003,6 +1038,11 @@ var OpenAIChatLanguageModel = class {
1003
1038
  if (text != null && text.length > 0) {
1004
1039
  content.push({ type: "text", text });
1005
1040
  }
1041
+ const refusal = choice.message.refusal;
1042
+ const hasRefusal = refusal != null && refusal.length > 0;
1043
+ if (hasRefusal) {
1044
+ content.push({ type: "text", text: refusal });
1045
+ }
1006
1046
  for (const toolCall of (_b = choice.message.tool_calls) != null ? _b : []) {
1007
1047
  content.push({
1008
1048
  type: "tool-call",
@@ -1034,18 +1074,26 @@ var OpenAIChatLanguageModel = class {
1034
1074
  cacheWriteTokens: promptTokenDetails.cache_write_tokens
1035
1075
  };
1036
1076
  }
1037
- if (((_g = choice.logprobs) == null ? void 0 : _g.content) != null) {
1038
- providerMetadata.openai.logprobs = choice.logprobs.content;
1077
+ const contentLogprobs = (_g = choice.logprobs) == null ? void 0 : _g.content;
1078
+ const refusalLogprobs = (_h = choice.logprobs) == null ? void 0 : _h.refusal;
1079
+ if (contentLogprobs != null || refusalLogprobs != null) {
1080
+ providerMetadata.openai.logprobs = [
1081
+ ...contentLogprobs != null ? contentLogprobs : [],
1082
+ ...refusalLogprobs != null ? refusalLogprobs : []
1083
+ ];
1039
1084
  }
1040
1085
  return {
1041
1086
  content,
1042
- finishReason: mapOpenAIFinishReason(choice.finish_reason),
1087
+ finishReason: mapOpenAIFinishReason({
1088
+ finishReason: choice.finish_reason,
1089
+ hasRefusal
1090
+ }),
1043
1091
  usage: {
1044
- inputTokens: (_i = (_h = response.usage) == null ? void 0 : _h.prompt_tokens) != null ? _i : void 0,
1045
- outputTokens: (_k = (_j = response.usage) == null ? void 0 : _j.completion_tokens) != null ? _k : void 0,
1046
- totalTokens: (_m = (_l = response.usage) == null ? void 0 : _l.total_tokens) != null ? _m : void 0,
1047
- reasoningTokens: (_n = completionTokenDetails == null ? void 0 : completionTokenDetails.reasoning_tokens) != null ? _n : void 0,
1048
- cachedInputTokens: (_o = promptTokenDetails == null ? void 0 : promptTokenDetails.cached_tokens) != null ? _o : void 0
1092
+ inputTokens: (_j = (_i = response.usage) == null ? void 0 : _i.prompt_tokens) != null ? _j : void 0,
1093
+ outputTokens: (_l = (_k = response.usage) == null ? void 0 : _k.completion_tokens) != null ? _l : void 0,
1094
+ totalTokens: (_n = (_m = response.usage) == null ? void 0 : _m.total_tokens) != null ? _n : void 0,
1095
+ reasoningTokens: (_o = completionTokenDetails == null ? void 0 : completionTokenDetails.reasoning_tokens) != null ? _o : void 0,
1096
+ cachedInputTokens: (_p = promptTokenDetails == null ? void 0 : promptTokenDetails.cached_tokens) != null ? _p : void 0
1049
1097
  },
1050
1098
  request: { body },
1051
1099
  response: {
@@ -1089,6 +1137,10 @@ var OpenAIChatLanguageModel = class {
1089
1137
  };
1090
1138
  let metadataExtracted = false;
1091
1139
  let isActiveText = false;
1140
+ let hasRefusal = false;
1141
+ let rawFinishReason = void 0;
1142
+ let hasLogprobs = false;
1143
+ const streamedLogprobs = [];
1092
1144
  const providerMetadata = { openai: {} };
1093
1145
  return {
1094
1146
  stream: response.pipeThrough(
@@ -1101,18 +1153,20 @@ var OpenAIChatLanguageModel = class {
1101
1153
  controller.enqueue({ type: "stream-start", warnings });
1102
1154
  },
1103
1155
  transform(chunk, controller) {
1104
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
1156
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
1105
1157
  if (options.includeRawChunks) {
1106
1158
  controller.enqueue({ type: "raw", rawValue: chunk.rawValue });
1107
1159
  }
1108
1160
  if (!chunk.success) {
1109
1161
  finishReason = "error";
1162
+ rawFinishReason = void 0;
1110
1163
  controller.enqueue({ type: "error", error: chunk.error });
1111
1164
  return;
1112
1165
  }
1113
1166
  const value = chunk.value;
1114
1167
  if ("error" in value) {
1115
1168
  finishReason = "error";
1169
+ rawFinishReason = void 0;
1116
1170
  controller.enqueue({ type: "error", error: value.error });
1117
1171
  return;
1118
1172
  }
@@ -1146,16 +1200,35 @@ var OpenAIChatLanguageModel = class {
1146
1200
  }
1147
1201
  const choice = value.choices[0];
1148
1202
  if ((choice == null ? void 0 : choice.finish_reason) != null) {
1149
- finishReason = mapOpenAIFinishReason(choice.finish_reason);
1203
+ rawFinishReason = choice.finish_reason;
1150
1204
  }
1151
- if (((_m = choice == null ? void 0 : choice.logprobs) == null ? void 0 : _m.content) != null) {
1152
- providerMetadata.openai.logprobs = choice.logprobs.content;
1205
+ if ((choice == null ? void 0 : choice.logprobs) != null) {
1206
+ const contentLogprobs = choice.logprobs.content;
1207
+ const refusalLogprobs = choice.logprobs.refusal;
1208
+ if (contentLogprobs != null || refusalLogprobs != null) {
1209
+ hasLogprobs = true;
1210
+ streamedLogprobs.push(
1211
+ ...contentLogprobs != null ? contentLogprobs : [],
1212
+ ...refusalLogprobs != null ? refusalLogprobs : []
1213
+ );
1214
+ }
1153
1215
  }
1154
1216
  if ((choice == null ? void 0 : choice.delta) == null) {
1155
1217
  return;
1156
1218
  }
1157
1219
  const delta = choice.delta;
1158
- if (delta.content != null) {
1220
+ const textDeltas = [];
1221
+ if (delta.content != null && delta.content.length > 0) {
1222
+ textDeltas.push(delta.content);
1223
+ }
1224
+ if (delta.refusal != null && delta.refusal.length > 0) {
1225
+ hasRefusal = true;
1226
+ textDeltas.push(delta.refusal);
1227
+ }
1228
+ if (textDeltas.length === 0 && delta.content === "") {
1229
+ textDeltas.push(delta.content);
1230
+ }
1231
+ for (const textDelta of textDeltas) {
1159
1232
  if (!isActiveText) {
1160
1233
  controller.enqueue({ type: "text-start", id: "0" });
1161
1234
  isActiveText = true;
@@ -1163,7 +1236,7 @@ var OpenAIChatLanguageModel = class {
1163
1236
  controller.enqueue({
1164
1237
  type: "text-delta",
1165
1238
  id: "0",
1166
- delta: delta.content
1239
+ delta: textDelta
1167
1240
  });
1168
1241
  }
1169
1242
  if (delta.tool_calls != null) {
@@ -1188,6 +1261,15 @@ var OpenAIChatLanguageModel = class {
1188
1261
  controller.enqueue({ type: "text-end", id: "0" });
1189
1262
  }
1190
1263
  toolCallTracker.flush();
1264
+ if (rawFinishReason != null) {
1265
+ finishReason = mapOpenAIFinishReason({
1266
+ finishReason: rawFinishReason,
1267
+ hasRefusal
1268
+ });
1269
+ }
1270
+ if (hasLogprobs) {
1271
+ providerMetadata.openai.logprobs = streamedLogprobs;
1272
+ }
1191
1273
  controller.enqueue({
1192
1274
  type: "finish",
1193
1275
  finishReason,
@@ -3136,12 +3218,14 @@ function serializeToolCallArguments2(input) {
3136
3218
  // src/responses/map-openai-responses-finish-reason.ts
3137
3219
  function mapOpenAIResponseFinishReason({
3138
3220
  finishReason,
3139
- hasFunctionCall
3221
+ hasFunctionCall,
3222
+ hasRefusal = false
3140
3223
  }) {
3141
3224
  switch (finishReason) {
3142
3225
  case void 0:
3143
3226
  case null:
3144
- return hasFunctionCall ? "tool-calls" : "stop";
3227
+ if (hasFunctionCall) return "tool-calls";
3228
+ return hasRefusal ? "content-filter" : "stop";
3145
3229
  case "max_output_tokens":
3146
3230
  return "length";
3147
3231
  case "content_filter":
@@ -3174,6 +3258,20 @@ var openaiResponsesChunkSchema = (0, import_provider_utils24.lazyValidator)(
3174
3258
  })
3175
3259
  ).nullish()
3176
3260
  }),
3261
+ import_v417.z.object({
3262
+ type: import_v417.z.literal("response.refusal.delta"),
3263
+ item_id: import_v417.z.string(),
3264
+ output_index: import_v417.z.number().nullish(),
3265
+ content_index: import_v417.z.number().nullish(),
3266
+ delta: import_v417.z.string()
3267
+ }),
3268
+ import_v417.z.object({
3269
+ type: import_v417.z.literal("response.refusal.done"),
3270
+ item_id: import_v417.z.string(),
3271
+ output_index: import_v417.z.number().nullish(),
3272
+ content_index: import_v417.z.number().nullish(),
3273
+ refusal: import_v417.z.string()
3274
+ }),
3177
3275
  import_v417.z.object({
3178
3276
  type: import_v417.z.enum(["response.completed", "response.incomplete"]),
3179
3277
  response: import_v417.z.object({
@@ -3460,57 +3558,64 @@ var openaiResponsesResponseSchema = (0, import_provider_utils24.lazyValidator)(
3460
3558
  role: import_v417.z.literal("assistant"),
3461
3559
  id: import_v417.z.string(),
3462
3560
  phase: import_v417.z.enum(["commentary", "final_answer"]).nullish(),
3561
+ // the API returns either text or a refusal as content parts:
3463
3562
  content: import_v417.z.array(
3464
- import_v417.z.object({
3465
- type: import_v417.z.literal("output_text"),
3466
- text: import_v417.z.string(),
3467
- logprobs: import_v417.z.array(
3468
- import_v417.z.object({
3469
- token: import_v417.z.string(),
3470
- logprob: import_v417.z.number(),
3471
- top_logprobs: import_v417.z.array(
3472
- import_v417.z.object({
3473
- token: import_v417.z.string(),
3474
- logprob: import_v417.z.number()
3475
- })
3476
- )
3477
- })
3478
- ).nullish(),
3479
- annotations: import_v417.z.array(
3480
- import_v417.z.discriminatedUnion("type", [
3481
- import_v417.z.object({
3482
- type: import_v417.z.literal("url_citation"),
3483
- start_index: import_v417.z.number(),
3484
- end_index: import_v417.z.number(),
3485
- url: import_v417.z.string(),
3486
- title: import_v417.z.string()
3487
- }),
3488
- import_v417.z.object({
3489
- type: import_v417.z.literal("file_citation"),
3490
- file_id: import_v417.z.string(),
3491
- filename: import_v417.z.string().nullish(),
3492
- index: import_v417.z.number().nullish(),
3493
- start_index: import_v417.z.number().nullish(),
3494
- end_index: import_v417.z.number().nullish(),
3495
- quote: import_v417.z.string().nullish()
3496
- }),
3497
- import_v417.z.object({
3498
- type: import_v417.z.literal("container_file_citation"),
3499
- container_id: import_v417.z.string(),
3500
- file_id: import_v417.z.string(),
3501
- filename: import_v417.z.string().nullish(),
3502
- start_index: import_v417.z.number().nullish(),
3503
- end_index: import_v417.z.number().nullish(),
3504
- index: import_v417.z.number().nullish()
3505
- }),
3563
+ import_v417.z.discriminatedUnion("type", [
3564
+ import_v417.z.object({
3565
+ type: import_v417.z.literal("output_text"),
3566
+ text: import_v417.z.string(),
3567
+ logprobs: import_v417.z.array(
3506
3568
  import_v417.z.object({
3507
- type: import_v417.z.literal("file_path"),
3508
- file_id: import_v417.z.string(),
3509
- index: import_v417.z.number().nullish()
3569
+ token: import_v417.z.string(),
3570
+ logprob: import_v417.z.number(),
3571
+ top_logprobs: import_v417.z.array(
3572
+ import_v417.z.object({
3573
+ token: import_v417.z.string(),
3574
+ logprob: import_v417.z.number()
3575
+ })
3576
+ )
3510
3577
  })
3511
- ])
3512
- )
3513
- })
3578
+ ).nullish(),
3579
+ annotations: import_v417.z.array(
3580
+ import_v417.z.discriminatedUnion("type", [
3581
+ import_v417.z.object({
3582
+ type: import_v417.z.literal("url_citation"),
3583
+ start_index: import_v417.z.number(),
3584
+ end_index: import_v417.z.number(),
3585
+ url: import_v417.z.string(),
3586
+ title: import_v417.z.string()
3587
+ }),
3588
+ import_v417.z.object({
3589
+ type: import_v417.z.literal("file_citation"),
3590
+ file_id: import_v417.z.string(),
3591
+ filename: import_v417.z.string().nullish(),
3592
+ index: import_v417.z.number().nullish(),
3593
+ start_index: import_v417.z.number().nullish(),
3594
+ end_index: import_v417.z.number().nullish(),
3595
+ quote: import_v417.z.string().nullish()
3596
+ }),
3597
+ import_v417.z.object({
3598
+ type: import_v417.z.literal("container_file_citation"),
3599
+ container_id: import_v417.z.string(),
3600
+ file_id: import_v417.z.string(),
3601
+ filename: import_v417.z.string().nullish(),
3602
+ start_index: import_v417.z.number().nullish(),
3603
+ end_index: import_v417.z.number().nullish(),
3604
+ index: import_v417.z.number().nullish()
3605
+ }),
3606
+ import_v417.z.object({
3607
+ type: import_v417.z.literal("file_path"),
3608
+ file_id: import_v417.z.string(),
3609
+ index: import_v417.z.number().nullish()
3610
+ })
3611
+ ])
3612
+ )
3613
+ }),
3614
+ import_v417.z.object({
3615
+ type: import_v417.z.literal("refusal"),
3616
+ refusal: import_v417.z.string()
3617
+ })
3618
+ ])
3514
3619
  )
3515
3620
  }),
3516
3621
  import_v417.z.object({
@@ -4354,6 +4459,7 @@ var OpenAIResponsesLanguageModel = class {
4354
4459
  const content = [];
4355
4460
  const logprobs = [];
4356
4461
  let hasFunctionCall = false;
4462
+ let hasRefusal = false;
4357
4463
  for (const part of response.output) {
4358
4464
  switch (part.type) {
4359
4465
  case "reasoning": {
@@ -4411,6 +4517,20 @@ var OpenAIResponsesLanguageModel = class {
4411
4517
  }
4412
4518
  case "message": {
4413
4519
  for (const contentPart of part.content) {
4520
+ if (contentPart.type === "refusal") {
4521
+ hasRefusal = true;
4522
+ content.push({
4523
+ type: "text",
4524
+ text: contentPart.refusal,
4525
+ providerMetadata: {
4526
+ [providerKey]: {
4527
+ itemId: part.id,
4528
+ ...part.phase != null && { phase: part.phase }
4529
+ }
4530
+ }
4531
+ });
4532
+ continue;
4533
+ }
4414
4534
  if (((_c = (_b = options.providerOptions) == null ? void 0 : _b.openai) == null ? void 0 : _c.logprobs) && contentPart.logprobs) {
4415
4535
  logprobs.push(contentPart.logprobs);
4416
4536
  }
@@ -4611,7 +4731,8 @@ var OpenAIResponsesLanguageModel = class {
4611
4731
  content,
4612
4732
  finishReason: mapOpenAIResponseFinishReason({
4613
4733
  finishReason: (_y = response.incomplete_details) == null ? void 0 : _y.reason,
4614
- hasFunctionCall
4734
+ hasFunctionCall,
4735
+ hasRefusal
4615
4736
  }),
4616
4737
  usage: {
4617
4738
  inputTokens: usage.input_tokens,
@@ -4670,6 +4791,7 @@ var OpenAIResponsesLanguageModel = class {
4670
4791
  const ongoingAnnotations = [];
4671
4792
  let activeMessagePhase;
4672
4793
  let hasFunctionCall = false;
4794
+ let hasRefusal = false;
4673
4795
  const activeReasoning = {};
4674
4796
  let serviceTier;
4675
4797
  let reasoningContext;
@@ -5011,6 +5133,15 @@ var OpenAIResponsesLanguageModel = class {
5011
5133
  if (((_h = (_g = options.providerOptions) == null ? void 0 : _g.openai) == null ? void 0 : _h.logprobs) && value.logprobs) {
5012
5134
  logprobs.push(value.logprobs);
5013
5135
  }
5136
+ } else if (isRefusalDeltaChunk(value)) {
5137
+ hasRefusal = true;
5138
+ controller.enqueue({
5139
+ type: "text-delta",
5140
+ id: value.item_id,
5141
+ delta: value.delta
5142
+ });
5143
+ } else if (isRefusalDoneChunk(value)) {
5144
+ hasRefusal = true;
5014
5145
  } else if (value.type === "response.reasoning_summary_part.added") {
5015
5146
  if (value.summary_index > 0) {
5016
5147
  const activeReasoningPart = activeReasoning[value.item_id];
@@ -5067,7 +5198,8 @@ var OpenAIResponsesLanguageModel = class {
5067
5198
  } else if (isResponseFinishedChunk(value)) {
5068
5199
  finishReason = mapOpenAIResponseFinishReason({
5069
5200
  finishReason: (_k = value.response.incomplete_details) == null ? void 0 : _k.reason,
5070
- hasFunctionCall
5201
+ hasFunctionCall,
5202
+ hasRefusal
5071
5203
  });
5072
5204
  usage.inputTokens = value.response.usage.input_tokens;
5073
5205
  usage.outputTokens = value.response.usage.output_tokens;
@@ -5144,6 +5276,12 @@ var OpenAIResponsesLanguageModel = class {
5144
5276
  };
5145
5277
  }
5146
5278
  };
5279
+ function isRefusalDeltaChunk(chunk) {
5280
+ return chunk.type === "response.refusal.delta";
5281
+ }
5282
+ function isRefusalDoneChunk(chunk) {
5283
+ return chunk.type === "response.refusal.done";
5284
+ }
5147
5285
  function isTextDeltaChunk(chunk) {
5148
5286
  return chunk.type === "response.output_text.delta";
5149
5287
  }