@ai-sdk/openai 3.0.137 → 3.0.139

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.
@@ -484,6 +484,18 @@ declare const openaiResponsesChunkSchema: _ai_sdk_provider_utils.LazySchema<{
484
484
  logprob: number;
485
485
  }[];
486
486
  }[] | null | undefined;
487
+ } | {
488
+ type: "response.refusal.delta";
489
+ item_id: string;
490
+ delta: string;
491
+ output_index?: number | null | undefined;
492
+ content_index?: number | null | undefined;
493
+ } | {
494
+ type: "response.refusal.done";
495
+ item_id: string;
496
+ refusal: string;
497
+ output_index?: number | null | undefined;
498
+ content_index?: number | null | undefined;
487
499
  } | {
488
500
  type: "response.completed" | "response.incomplete";
489
501
  response: {
@@ -484,6 +484,18 @@ declare const openaiResponsesChunkSchema: _ai_sdk_provider_utils.LazySchema<{
484
484
  logprob: number;
485
485
  }[];
486
486
  }[] | null | undefined;
487
+ } | {
488
+ type: "response.refusal.delta";
489
+ item_id: string;
490
+ delta: string;
491
+ output_index?: number | null | undefined;
492
+ content_index?: number | null | undefined;
493
+ } | {
494
+ type: "response.refusal.done";
495
+ item_id: string;
496
+ refusal: string;
497
+ output_index?: number | null | undefined;
498
+ content_index?: number | null | undefined;
487
499
  } | {
488
500
  type: "response.completed" | "response.incomplete";
489
501
  response: {
@@ -698,10 +698,13 @@ function getResponseMetadata({
698
698
  }
699
699
 
700
700
  // src/chat/map-openai-finish-reason.ts
701
- function mapOpenAIFinishReason(finishReason) {
701
+ function mapOpenAIFinishReason({
702
+ finishReason,
703
+ hasRefusal = false
704
+ }) {
702
705
  switch (finishReason) {
703
706
  case "stop":
704
- return "stop";
707
+ return hasRefusal ? "content-filter" : "stop";
705
708
  case "length":
706
709
  return "length";
707
710
  case "content_filter":
@@ -728,6 +731,8 @@ var openaiChatResponseSchema = (0, import_provider_utils3.lazySchema)(
728
731
  message: import_v42.z.object({
729
732
  role: import_v42.z.literal("assistant").nullish(),
730
733
  content: import_v42.z.string().nullish(),
734
+ // set instead of `content` when the model refuses to answer:
735
+ refusal: import_v42.z.string().nullish(),
731
736
  audio: import_v42.z.object({
732
737
  transcript: import_v42.z.string().nullish()
733
738
  }).nullish(),
@@ -766,6 +771,20 @@ var openaiChatResponseSchema = (0, import_provider_utils3.lazySchema)(
766
771
  })
767
772
  )
768
773
  })
774
+ ).nullish(),
775
+ // logprobs of the refusal tokens (set instead of `content` when
776
+ // the model refuses to answer):
777
+ refusal: import_v42.z.array(
778
+ import_v42.z.object({
779
+ token: import_v42.z.string(),
780
+ logprob: import_v42.z.number(),
781
+ top_logprobs: import_v42.z.array(
782
+ import_v42.z.object({
783
+ token: import_v42.z.string(),
784
+ logprob: import_v42.z.number()
785
+ })
786
+ )
787
+ })
769
788
  ).nullish()
770
789
  }).nullish(),
771
790
  finish_reason: import_v42.z.string().nullish()
@@ -800,6 +819,8 @@ var openaiChatChunkSchema = (0, import_provider_utils3.lazySchema)(
800
819
  delta: import_v42.z.object({
801
820
  role: import_v42.z.enum(["assistant"]).nullish(),
802
821
  content: import_v42.z.string().nullish(),
822
+ // set instead of `content` when the model refuses to answer:
823
+ refusal: import_v42.z.string().nullish(),
803
824
  tool_calls: import_v42.z.array(
804
825
  import_v42.z.object({
805
826
  index: import_v42.z.number(),
@@ -835,6 +856,20 @@ var openaiChatChunkSchema = (0, import_provider_utils3.lazySchema)(
835
856
  })
836
857
  )
837
858
  })
859
+ ).nullish(),
860
+ // logprobs of the refusal tokens (set instead of `content` when
861
+ // the model refuses to answer):
862
+ refusal: import_v42.z.array(
863
+ import_v42.z.object({
864
+ token: import_v42.z.string(),
865
+ logprob: import_v42.z.number(),
866
+ top_logprobs: import_v42.z.array(
867
+ import_v42.z.object({
868
+ token: import_v42.z.string(),
869
+ logprob: import_v42.z.number()
870
+ })
871
+ )
872
+ })
838
873
  ).nullish()
839
874
  }).nullish(),
840
875
  finish_reason: import_v42.z.string().nullish(),
@@ -1271,7 +1306,7 @@ var OpenAIChatLanguageModel = class {
1271
1306
  };
1272
1307
  }
1273
1308
  async doGenerate(options) {
1274
- var _a2, _b, _c, _d, _e, _f, _g, _h;
1309
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i;
1275
1310
  const { args: body, warnings } = await this.getArgs(options);
1276
1311
  const {
1277
1312
  responseHeaders,
@@ -1303,6 +1338,11 @@ var OpenAIChatLanguageModel = class {
1303
1338
  if (text != null && text.length > 0) {
1304
1339
  content.push({ type: "text", text });
1305
1340
  }
1341
+ const refusal = choice.message.refusal;
1342
+ const hasRefusal = refusal != null && refusal.length > 0;
1343
+ if (hasRefusal) {
1344
+ content.push({ type: "text", text: refusal });
1345
+ }
1306
1346
  for (const toolCall of (_b = choice.message.tool_calls) != null ? _b : []) {
1307
1347
  content.push({
1308
1348
  type: "tool-call",
@@ -1329,14 +1369,22 @@ var OpenAIChatLanguageModel = class {
1329
1369
  if ((completionTokenDetails == null ? void 0 : completionTokenDetails.rejected_prediction_tokens) != null) {
1330
1370
  providerMetadata.openai.rejectedPredictionTokens = completionTokenDetails == null ? void 0 : completionTokenDetails.rejected_prediction_tokens;
1331
1371
  }
1332
- if (((_g = choice.logprobs) == null ? void 0 : _g.content) != null) {
1333
- providerMetadata.openai.logprobs = choice.logprobs.content;
1372
+ const contentLogprobs = (_g = choice.logprobs) == null ? void 0 : _g.content;
1373
+ const refusalLogprobs = (_h = choice.logprobs) == null ? void 0 : _h.refusal;
1374
+ if (contentLogprobs != null || refusalLogprobs != null) {
1375
+ providerMetadata.openai.logprobs = [
1376
+ ...contentLogprobs != null ? contentLogprobs : [],
1377
+ ...refusalLogprobs != null ? refusalLogprobs : []
1378
+ ];
1334
1379
  }
1335
1380
  return {
1336
1381
  content,
1337
1382
  finishReason: {
1338
- unified: mapOpenAIFinishReason(choice.finish_reason),
1339
- raw: (_h = choice.finish_reason) != null ? _h : void 0
1383
+ unified: mapOpenAIFinishReason({
1384
+ finishReason: choice.finish_reason,
1385
+ hasRefusal
1386
+ }),
1387
+ raw: (_i = choice.finish_reason) != null ? _i : void 0
1340
1388
  },
1341
1389
  usage: convertOpenAIChatUsage(response.usage),
1342
1390
  request: { body },
@@ -1389,6 +1437,10 @@ var OpenAIChatLanguageModel = class {
1389
1437
  let usage = void 0;
1390
1438
  let metadataExtracted = false;
1391
1439
  let isActiveText = false;
1440
+ let hasRefusal = false;
1441
+ let rawFinishReason = void 0;
1442
+ let hasLogprobs = false;
1443
+ const streamedLogprobs = [];
1392
1444
  const providerMetadata = { openai: {} };
1393
1445
  const result = {
1394
1446
  stream: checkedResponse.pipeThrough(
@@ -1401,18 +1453,20 @@ var OpenAIChatLanguageModel = class {
1401
1453
  controller.enqueue({ type: "stream-start", warnings });
1402
1454
  },
1403
1455
  transform(chunk, controller) {
1404
- var _a2, _b, _c, _d, _e;
1456
+ var _a2, _b, _c, _d;
1405
1457
  if (options.includeRawChunks) {
1406
1458
  controller.enqueue({ type: "raw", rawValue: chunk.rawValue });
1407
1459
  }
1408
1460
  if (!chunk.success) {
1409
1461
  finishReason = { unified: "error", raw: void 0 };
1462
+ rawFinishReason = void 0;
1410
1463
  controller.enqueue({ type: "error", error: chunk.error });
1411
1464
  return;
1412
1465
  }
1413
1466
  const value = chunk.value;
1414
1467
  if ("error" in value) {
1415
1468
  finishReason = { unified: "error", raw: void 0 };
1469
+ rawFinishReason = void 0;
1416
1470
  controller.enqueue({ type: "error", error: value.error });
1417
1471
  return;
1418
1472
  }
@@ -1437,19 +1491,35 @@ var OpenAIChatLanguageModel = class {
1437
1491
  }
1438
1492
  const choice = value.choices[0];
1439
1493
  if ((choice == null ? void 0 : choice.finish_reason) != null) {
1440
- finishReason = {
1441
- unified: mapOpenAIFinishReason(choice.finish_reason),
1442
- raw: choice.finish_reason
1443
- };
1494
+ rawFinishReason = choice.finish_reason;
1444
1495
  }
1445
- if (((_e = choice == null ? void 0 : choice.logprobs) == null ? void 0 : _e.content) != null) {
1446
- providerMetadata.openai.logprobs = choice.logprobs.content;
1496
+ if ((choice == null ? void 0 : choice.logprobs) != null) {
1497
+ const contentLogprobs = choice.logprobs.content;
1498
+ const refusalLogprobs = choice.logprobs.refusal;
1499
+ if (contentLogprobs != null || refusalLogprobs != null) {
1500
+ hasLogprobs = true;
1501
+ streamedLogprobs.push(
1502
+ ...contentLogprobs != null ? contentLogprobs : [],
1503
+ ...refusalLogprobs != null ? refusalLogprobs : []
1504
+ );
1505
+ }
1447
1506
  }
1448
1507
  if ((choice == null ? void 0 : choice.delta) == null) {
1449
1508
  return;
1450
1509
  }
1451
1510
  const delta = choice.delta;
1452
- if (delta.content != null) {
1511
+ const textDeltas = [];
1512
+ if (delta.content != null && delta.content.length > 0) {
1513
+ textDeltas.push(delta.content);
1514
+ }
1515
+ if (delta.refusal != null && delta.refusal.length > 0) {
1516
+ hasRefusal = true;
1517
+ textDeltas.push(delta.refusal);
1518
+ }
1519
+ if (textDeltas.length === 0 && delta.content === "") {
1520
+ textDeltas.push(delta.content);
1521
+ }
1522
+ for (const textDelta of textDeltas) {
1453
1523
  if (!isActiveText) {
1454
1524
  controller.enqueue({ type: "text-start", id: "0" });
1455
1525
  isActiveText = true;
@@ -1457,7 +1527,7 @@ var OpenAIChatLanguageModel = class {
1457
1527
  controller.enqueue({
1458
1528
  type: "text-delta",
1459
1529
  id: "0",
1460
- delta: delta.content
1530
+ delta: textDelta
1461
1531
  });
1462
1532
  }
1463
1533
  if (delta.tool_calls != null) {
@@ -1482,6 +1552,18 @@ var OpenAIChatLanguageModel = class {
1482
1552
  controller.enqueue({ type: "text-end", id: "0" });
1483
1553
  }
1484
1554
  toolCallTracker.flush();
1555
+ if (rawFinishReason != null) {
1556
+ finishReason = {
1557
+ unified: mapOpenAIFinishReason({
1558
+ finishReason: rawFinishReason,
1559
+ hasRefusal
1560
+ }),
1561
+ raw: rawFinishReason
1562
+ };
1563
+ }
1564
+ if (hasLogprobs) {
1565
+ providerMetadata.openai.logprobs = streamedLogprobs;
1566
+ }
1485
1567
  controller.enqueue({
1486
1568
  type: "finish",
1487
1569
  finishReason,
@@ -1503,7 +1585,7 @@ function isOpenAIChatOutputChunk(chunk) {
1503
1585
  }
1504
1586
  return chunk.choices.some((choice) => {
1505
1587
  const delta = choice.delta;
1506
- return (delta == null ? void 0 : delta.content) != null && delta.content.length > 0 || (delta == null ? void 0 : delta.tool_calls) != null && delta.tool_calls.length > 0 || (delta == null ? void 0 : delta.annotations) != null && delta.annotations.length > 0;
1588
+ return (delta == null ? void 0 : delta.content) != null && delta.content.length > 0 || (delta == null ? void 0 : delta.refusal) != null && delta.refusal.length > 0 || (delta == null ? void 0 : delta.tool_calls) != null && delta.tool_calls.length > 0 || (delta == null ? void 0 : delta.annotations) != null && delta.annotations.length > 0;
1507
1589
  });
1508
1590
  }
1509
1591
 
@@ -4615,12 +4697,14 @@ var openaiResponsesReasoningProviderOptionsSchema = (0, import_provider_utils27.
4615
4697
  // src/responses/map-openai-responses-finish-reason.ts
4616
4698
  function mapOpenAIResponseFinishReason({
4617
4699
  finishReason,
4618
- hasFunctionCall
4700
+ hasFunctionCall,
4701
+ hasRefusal = false
4619
4702
  }) {
4620
4703
  switch (finishReason) {
4621
4704
  case void 0:
4622
4705
  case null:
4623
- return hasFunctionCall ? "tool-calls" : "stop";
4706
+ if (hasFunctionCall) return "tool-calls";
4707
+ return hasRefusal ? "content-filter" : "stop";
4624
4708
  case "max_output_tokens":
4625
4709
  return "length";
4626
4710
  case "content_filter":
@@ -4727,6 +4811,8 @@ var openaiResponsesModeledChunkTypes = /* @__PURE__ */ new Set([
4727
4811
  "response.output_item.done",
4728
4812
  "response.output_text.annotation.added",
4729
4813
  "response.output_text.delta",
4814
+ "response.refusal.delta",
4815
+ "response.refusal.done",
4730
4816
  "response.reasoning_summary_part.added",
4731
4817
  "response.reasoning_summary_part.done",
4732
4818
  "response.reasoning_summary_text.delta"
@@ -4783,6 +4869,20 @@ var openaiResponsesChunkSchema = (0, import_provider_utils28.lazySchema)(
4783
4869
  })
4784
4870
  ).nullish()
4785
4871
  }),
4872
+ import_v420.z.object({
4873
+ type: import_v420.z.literal("response.refusal.delta"),
4874
+ item_id: import_v420.z.string(),
4875
+ output_index: import_v420.z.number().nullish(),
4876
+ content_index: import_v420.z.number().nullish(),
4877
+ delta: import_v420.z.string()
4878
+ }),
4879
+ import_v420.z.object({
4880
+ type: import_v420.z.literal("response.refusal.done"),
4881
+ item_id: import_v420.z.string(),
4882
+ output_index: import_v420.z.number().nullish(),
4883
+ content_index: import_v420.z.number().nullish(),
4884
+ refusal: import_v420.z.string()
4885
+ }),
4786
4886
  import_v420.z.object({
4787
4887
  type: import_v420.z.enum(["response.completed", "response.incomplete"]),
4788
4888
  response: import_v420.z.object({
@@ -5308,53 +5408,60 @@ var openaiResponsesResponseSchema = (0, import_provider_utils28.lazySchema)(
5308
5408
  role: import_v420.z.literal("assistant"),
5309
5409
  id: import_v420.z.string(),
5310
5410
  phase: import_v420.z.enum(["commentary", "final_answer"]).nullish(),
5411
+ // the API returns either text or a refusal as content parts:
5311
5412
  content: import_v420.z.array(
5312
- import_v420.z.object({
5313
- type: import_v420.z.literal("output_text"),
5314
- text: import_v420.z.string(),
5315
- logprobs: import_v420.z.array(
5316
- import_v420.z.object({
5317
- token: import_v420.z.string(),
5318
- logprob: import_v420.z.number(),
5319
- top_logprobs: import_v420.z.array(
5320
- import_v420.z.object({
5321
- token: import_v420.z.string(),
5322
- logprob: import_v420.z.number()
5323
- })
5324
- )
5325
- })
5326
- ).nullish(),
5327
- annotations: import_v420.z.array(
5328
- import_v420.z.discriminatedUnion("type", [
5329
- import_v420.z.object({
5330
- type: import_v420.z.literal("url_citation"),
5331
- start_index: import_v420.z.number(),
5332
- end_index: import_v420.z.number(),
5333
- url: import_v420.z.string(),
5334
- title: import_v420.z.string()
5335
- }),
5336
- import_v420.z.object({
5337
- type: import_v420.z.literal("file_citation"),
5338
- file_id: import_v420.z.string(),
5339
- filename: import_v420.z.string(),
5340
- index: import_v420.z.number()
5341
- }),
5342
- import_v420.z.object({
5343
- type: import_v420.z.literal("container_file_citation"),
5344
- container_id: import_v420.z.string(),
5345
- file_id: import_v420.z.string(),
5346
- filename: import_v420.z.string(),
5347
- start_index: import_v420.z.number(),
5348
- end_index: import_v420.z.number()
5349
- }),
5413
+ import_v420.z.discriminatedUnion("type", [
5414
+ import_v420.z.object({
5415
+ type: import_v420.z.literal("output_text"),
5416
+ text: import_v420.z.string(),
5417
+ logprobs: import_v420.z.array(
5350
5418
  import_v420.z.object({
5351
- type: import_v420.z.literal("file_path"),
5352
- file_id: import_v420.z.string(),
5353
- index: import_v420.z.number()
5419
+ token: import_v420.z.string(),
5420
+ logprob: import_v420.z.number(),
5421
+ top_logprobs: import_v420.z.array(
5422
+ import_v420.z.object({
5423
+ token: import_v420.z.string(),
5424
+ logprob: import_v420.z.number()
5425
+ })
5426
+ )
5354
5427
  })
5355
- ])
5356
- )
5357
- })
5428
+ ).nullish(),
5429
+ annotations: import_v420.z.array(
5430
+ import_v420.z.discriminatedUnion("type", [
5431
+ import_v420.z.object({
5432
+ type: import_v420.z.literal("url_citation"),
5433
+ start_index: import_v420.z.number(),
5434
+ end_index: import_v420.z.number(),
5435
+ url: import_v420.z.string(),
5436
+ title: import_v420.z.string()
5437
+ }),
5438
+ import_v420.z.object({
5439
+ type: import_v420.z.literal("file_citation"),
5440
+ file_id: import_v420.z.string(),
5441
+ filename: import_v420.z.string(),
5442
+ index: import_v420.z.number()
5443
+ }),
5444
+ import_v420.z.object({
5445
+ type: import_v420.z.literal("container_file_citation"),
5446
+ container_id: import_v420.z.string(),
5447
+ file_id: import_v420.z.string(),
5448
+ filename: import_v420.z.string(),
5449
+ start_index: import_v420.z.number(),
5450
+ end_index: import_v420.z.number()
5451
+ }),
5452
+ import_v420.z.object({
5453
+ type: import_v420.z.literal("file_path"),
5454
+ file_id: import_v420.z.string(),
5455
+ index: import_v420.z.number()
5456
+ })
5457
+ ])
5458
+ )
5459
+ }),
5460
+ import_v420.z.object({
5461
+ type: import_v420.z.literal("refusal"),
5462
+ refusal: import_v420.z.string()
5463
+ })
5464
+ ])
5358
5465
  )
5359
5466
  }),
5360
5467
  import_v420.z.object({
@@ -6758,6 +6865,7 @@ var OpenAIResponsesLanguageModel = class {
6758
6865
  )) != null ? _b : [];
6759
6866
  let hasFunctionCall = false;
6760
6867
  const hostedToolSearchCallIds = [];
6868
+ let hasRefusal = false;
6761
6869
  for (const part of response.output) {
6762
6870
  switch (part.type) {
6763
6871
  case "reasoning": {
@@ -6891,6 +6999,20 @@ var OpenAIResponsesLanguageModel = class {
6891
6999
  }
6892
7000
  case "message": {
6893
7001
  for (const contentPart of part.content) {
7002
+ if (contentPart.type === "refusal") {
7003
+ hasRefusal = true;
7004
+ content.push({
7005
+ type: "text",
7006
+ text: contentPart.refusal,
7007
+ providerMetadata: {
7008
+ [providerOptionsName]: {
7009
+ itemId: part.id,
7010
+ ...part.phase != null && { phase: part.phase }
7011
+ }
7012
+ }
7013
+ });
7014
+ continue;
7015
+ }
6894
7016
  if (((_h = (_g = options.providerOptions) == null ? void 0 : _g[providerOptionsName]) == null ? void 0 : _h.logprobs) && contentPart.logprobs) {
6895
7017
  logprobs.push(contentPart.logprobs);
6896
7018
  }
@@ -7190,7 +7312,8 @@ var OpenAIResponsesLanguageModel = class {
7190
7312
  finishReason: {
7191
7313
  unified: mapOpenAIResponseFinishReason({
7192
7314
  finishReason: (_C = response.incomplete_details) == null ? void 0 : _C.reason,
7193
- hasFunctionCall
7315
+ hasFunctionCall,
7316
+ hasRefusal
7194
7317
  }),
7195
7318
  raw: (_E = (_D = response.incomplete_details) == null ? void 0 : _D.reason) != null ? _E : void 0
7196
7319
  },
@@ -7261,6 +7384,7 @@ var OpenAIResponsesLanguageModel = class {
7261
7384
  const ongoingAnnotations = [];
7262
7385
  let activeMessagePhase;
7263
7386
  let hasFunctionCall = false;
7387
+ let hasRefusal = false;
7264
7388
  const activeReasoning = {};
7265
7389
  let serviceTier;
7266
7390
  let reasoningContext;
@@ -8034,6 +8158,15 @@ var OpenAIResponsesLanguageModel = class {
8034
8158
  if (((_u = (_t = options.providerOptions) == null ? void 0 : _t[providerOptionsName]) == null ? void 0 : _u.logprobs) && value.logprobs) {
8035
8159
  logprobs.push(value.logprobs);
8036
8160
  }
8161
+ } else if (isRefusalDeltaChunk(value)) {
8162
+ hasRefusal = true;
8163
+ controller.enqueue({
8164
+ type: "text-delta",
8165
+ id: value.item_id,
8166
+ delta: value.delta
8167
+ });
8168
+ } else if (isRefusalDoneChunk(value)) {
8169
+ hasRefusal = true;
8037
8170
  } else if (value.type === "response.reasoning_summary_part.added") {
8038
8171
  if (value.summary_index > 0) {
8039
8172
  const activeReasoningPart = activeReasoning[value.item_id];
@@ -8096,7 +8229,8 @@ var OpenAIResponsesLanguageModel = class {
8096
8229
  finishReason = {
8097
8230
  unified: mapOpenAIResponseFinishReason({
8098
8231
  finishReason: (_x = value.response.incomplete_details) == null ? void 0 : _x.reason,
8099
- hasFunctionCall
8232
+ hasFunctionCall,
8233
+ hasRefusal
8100
8234
  }),
8101
8235
  raw: (_z = (_y = value.response.incomplete_details) == null ? void 0 : _y.reason) != null ? _z : void 0
8102
8236
  };
@@ -8250,6 +8384,12 @@ var OpenAIResponsesLanguageModel = class {
8250
8384
  function isTextDeltaChunk(chunk) {
8251
8385
  return chunk.type === "response.output_text.delta";
8252
8386
  }
8387
+ function isRefusalDeltaChunk(chunk) {
8388
+ return chunk.type === "response.refusal.delta";
8389
+ }
8390
+ function isRefusalDoneChunk(chunk) {
8391
+ return chunk.type === "response.refusal.done";
8392
+ }
8253
8393
  function isOpenAIChatCompletionChunk(value) {
8254
8394
  const chunk = asRecord2(value);
8255
8395
  return chunk != null && Array.isArray(chunk.choices) && typeof chunk.type !== "string";