@ai-sdk/openai 2.0.139 → 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/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # @ai-sdk/openai
2
2
 
3
+ ## 2.0.141
4
+
5
+ ### Patch Changes
6
+
7
+ - 6b6433f: fix(openai): surface Chat Completions refusals as text content
8
+
9
+ The Chat Completions model ignored `message.refusal` (non-streaming) and `delta.refusal` (streaming). When the model refused to answer, `content` was `null`, so the AI SDK returned empty text with a `stop` finish reason and silently dropped the refusal. Refusal text is now emitted as text content in both `generateText` and `streamText` results, and it is emitted in addition to content when the API returns both. A refusal with a `stop` finish reason is now reported as a `content-filter` finish reason, matching the Anthropic provider and the Responses API.
10
+
11
+ - ce27f15: fix(openai,openai-compatible): surface refusal logprobs and openai-compatible refusals
12
+
13
+ `@ai-sdk/openai`: Chat Completions responses that contain a refusal can return `logprobs.refusal` next to `logprobs.content`. The provider previously read only `logprobs.content`, so `providerMetadata.openai.logprobs` was empty or missing for refusals. Refusal logprobs are now included in emission order (content logprobs followed by refusal logprobs) in both `generateText` and `streamText`.
14
+
15
+ Streaming logprobs are now collected across all chunks in `streamText`: previously only the logprobs of the last streamed chunk were reported. This applies to content logprobs as well, so `providerMetadata.openai.logprobs` now contains the logprobs of every streamed token instead of only the last chunk's tokens. Explicitly empty logprobs (`logprobs: { content: [], refusal: null }`) are reported as an empty array, as before.
16
+
17
+ A refusal that arrives in the same streamed chunk as the `finish_reason` is now taken into account: such a response is reported with a `content-filter` finish reason instead of `stop`.
18
+
19
+ `@ai-sdk/openai-compatible`: Chat Completions responses that carry `message.refusal` (non-streaming) or `delta.refusal` (streaming) were ignored, so providers such as OpenAI served through `createOpenAICompatible` lost the refusal text and reported an empty `stop` response. Refusals are now returned as text content after any content text, and a non-empty refusal with a `stop` finish reason is reported as a `content-filter` finish reason. This also applies when the refusal and the finish reason arrive in the same streamed chunk. Non-string refusals (for example `refusal: false` from servers that use booleans) are ignored instead of failing the response.
20
+
21
+ - 0e51536: fix(openai): handle refusal content parts in the Responses API
22
+
23
+ The Responses API returns a `refusal` content part instead of `output_text` when the model declines a request. The response schema rejected these parts, so non-streaming calls failed with an `APICallError` ("Invalid JSON response"), and streamed `response.refusal.delta` / `response.refusal.done` events were dropped, producing empty text. Refusal content parts and stream events are now parsed: the refusal explanation is surfaced as text and the finish reason is mapped to `content-filter`. When the response also contains a client-side function call, the finish reason stays `tool-calls` so the tools are still executed.
24
+
25
+ - Updated dependencies [49c554d]
26
+ - Updated dependencies [b753c03]
27
+ - @ai-sdk/provider-utils@3.0.45
28
+
29
+ ## 2.0.140
30
+
31
+ ### Patch Changes
32
+
33
+ - 0a069bd: fix(openai): preserve valid JSON string tool arguments and serialize BigInt and cycles in tool calls and results, retaining malformed argument replay fallbacks
34
+ - 0a069bd: Forward `languages` and `keywords` transcription hints as repeated multipart fields instead of silently dropping them.
35
+ - Updated dependencies [0a069bd]
36
+ - Updated dependencies [0a069bd]
37
+ - Updated dependencies [0a069bd]
38
+ - @ai-sdk/provider-utils@3.0.44
39
+
3
40
  ## 2.0.139
4
41
 
5
42
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -202,6 +202,18 @@ declare const openaiResponsesChunkSchema: _ai_sdk_provider_utils.LazyValidator<{
202
202
  logprob: number;
203
203
  }[];
204
204
  }[] | null | undefined;
205
+ } | {
206
+ type: "response.refusal.delta";
207
+ item_id: string;
208
+ delta: string;
209
+ output_index?: number | null | undefined;
210
+ content_index?: number | null | undefined;
211
+ } | {
212
+ type: "response.refusal.done";
213
+ item_id: string;
214
+ refusal: string;
215
+ output_index?: number | null | undefined;
216
+ content_index?: number | null | undefined;
205
217
  } | {
206
218
  type: "response.completed" | "response.incomplete";
207
219
  response: {
package/dist/index.d.ts CHANGED
@@ -202,6 +202,18 @@ declare const openaiResponsesChunkSchema: _ai_sdk_provider_utils.LazyValidator<{
202
202
  logprob: number;
203
203
  }[];
204
204
  }[] | null | undefined;
205
+ } | {
206
+ type: "response.refusal.delta";
207
+ item_id: string;
208
+ delta: string;
209
+ output_index?: number | null | undefined;
210
+ content_index?: number | null | undefined;
211
+ } | {
212
+ type: "response.refusal.done";
213
+ item_id: string;
214
+ refusal: string;
215
+ output_index?: number | null | undefined;
216
+ content_index?: number | null | undefined;
205
217
  } | {
206
218
  type: "response.completed" | "response.incomplete";
207
219
  response: {
package/dist/index.js CHANGED
@@ -100,7 +100,18 @@ function getGptVersion(modelId) {
100
100
  var import_provider = require("@ai-sdk/provider");
101
101
  var import_provider_utils2 = require("@ai-sdk/provider-utils");
102
102
  function serializeToolCallArguments(input) {
103
- return JSON.stringify(
103
+ if (typeof input === "string") {
104
+ try {
105
+ const parsed = (0, import_provider_utils2.secureJsonParse)(input);
106
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
107
+ return "{}";
108
+ }
109
+ return input;
110
+ } catch (e) {
111
+ return "{}";
112
+ }
113
+ }
114
+ return (0, import_provider_utils2.stringifyWithBigIntAndCycles)(
104
115
  typeof input === "object" && input !== null && !Array.isArray(input) ? input : {}
105
116
  );
106
117
  }
@@ -323,7 +334,7 @@ function convertToOpenAIChatMessages({
323
334
  case "content":
324
335
  case "json":
325
336
  case "error-json":
326
- contentValue = JSON.stringify(output.value);
337
+ contentValue = (0, import_provider_utils2.stringifyWithBigIntAndCycles)(output.value);
327
338
  break;
328
339
  }
329
340
  messages.push({
@@ -363,10 +374,13 @@ function getResponseMetadata({
363
374
  }
364
375
 
365
376
  // src/chat/map-openai-finish-reason.ts
366
- function mapOpenAIFinishReason(finishReason) {
377
+ function mapOpenAIFinishReason({
378
+ finishReason,
379
+ hasRefusal = false
380
+ }) {
367
381
  switch (finishReason) {
368
382
  case "stop":
369
- return "stop";
383
+ return hasRefusal ? "content-filter" : "stop";
370
384
  case "length":
371
385
  return "length";
372
386
  case "content_filter":
@@ -393,6 +407,8 @@ var openaiChatResponseSchema = (0, import_provider_utils3.lazyValidator)(
393
407
  message: import_v42.z.object({
394
408
  role: import_v42.z.literal("assistant").nullish(),
395
409
  content: import_v42.z.string().nullish(),
410
+ // set instead of `content` when the model refuses to answer:
411
+ refusal: import_v42.z.string().nullish(),
396
412
  audio: import_v42.z.object({
397
413
  transcript: import_v42.z.string().nullish()
398
414
  }).nullish(),
@@ -431,6 +447,20 @@ var openaiChatResponseSchema = (0, import_provider_utils3.lazyValidator)(
431
447
  })
432
448
  )
433
449
  })
450
+ ).nullish(),
451
+ // logprobs of the refusal tokens (set instead of `content` when
452
+ // the model refuses to answer):
453
+ refusal: import_v42.z.array(
454
+ import_v42.z.object({
455
+ token: import_v42.z.string(),
456
+ logprob: import_v42.z.number(),
457
+ top_logprobs: import_v42.z.array(
458
+ import_v42.z.object({
459
+ token: import_v42.z.string(),
460
+ logprob: import_v42.z.number()
461
+ })
462
+ )
463
+ })
434
464
  ).nullish()
435
465
  }).nullish(),
436
466
  finish_reason: import_v42.z.string().nullish()
@@ -465,6 +495,8 @@ var openaiChatChunkSchema = (0, import_provider_utils3.lazyValidator)(
465
495
  delta: import_v42.z.object({
466
496
  role: import_v42.z.enum(["assistant"]).nullish(),
467
497
  content: import_v42.z.string().nullish(),
498
+ // set instead of `content` when the model refuses to answer:
499
+ refusal: import_v42.z.string().nullish(),
468
500
  tool_calls: import_v42.z.array(
469
501
  import_v42.z.object({
470
502
  index: import_v42.z.number(),
@@ -500,6 +532,20 @@ var openaiChatChunkSchema = (0, import_provider_utils3.lazyValidator)(
500
532
  })
501
533
  )
502
534
  })
535
+ ).nullish(),
536
+ // logprobs of the refusal tokens (set instead of `content` when
537
+ // the model refuses to answer):
538
+ refusal: import_v42.z.array(
539
+ import_v42.z.object({
540
+ token: import_v42.z.string(),
541
+ logprob: import_v42.z.number(),
542
+ top_logprobs: import_v42.z.array(
543
+ import_v42.z.object({
544
+ token: import_v42.z.string(),
545
+ logprob: import_v42.z.number()
546
+ })
547
+ )
548
+ })
503
549
  ).nullish()
504
550
  }).nullish(),
505
551
  finish_reason: import_v42.z.string().nullish(),
@@ -931,7 +977,7 @@ var OpenAIChatLanguageModel = class {
931
977
  };
932
978
  }
933
979
  async doGenerate(options) {
934
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
980
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
935
981
  const { args: body, warnings } = await this.getArgs(options);
936
982
  const {
937
983
  responseHeaders,
@@ -963,6 +1009,11 @@ var OpenAIChatLanguageModel = class {
963
1009
  if (text != null && text.length > 0) {
964
1010
  content.push({ type: "text", text });
965
1011
  }
1012
+ const refusal = choice.message.refusal;
1013
+ const hasRefusal = refusal != null && refusal.length > 0;
1014
+ if (hasRefusal) {
1015
+ content.push({ type: "text", text: refusal });
1016
+ }
966
1017
  for (const toolCall of (_b = choice.message.tool_calls) != null ? _b : []) {
967
1018
  content.push({
968
1019
  type: "tool-call",
@@ -994,18 +1045,26 @@ var OpenAIChatLanguageModel = class {
994
1045
  cacheWriteTokens: promptTokenDetails.cache_write_tokens
995
1046
  };
996
1047
  }
997
- if (((_g = choice.logprobs) == null ? void 0 : _g.content) != null) {
998
- providerMetadata.openai.logprobs = choice.logprobs.content;
1048
+ const contentLogprobs = (_g = choice.logprobs) == null ? void 0 : _g.content;
1049
+ const refusalLogprobs = (_h = choice.logprobs) == null ? void 0 : _h.refusal;
1050
+ if (contentLogprobs != null || refusalLogprobs != null) {
1051
+ providerMetadata.openai.logprobs = [
1052
+ ...contentLogprobs != null ? contentLogprobs : [],
1053
+ ...refusalLogprobs != null ? refusalLogprobs : []
1054
+ ];
999
1055
  }
1000
1056
  return {
1001
1057
  content,
1002
- finishReason: mapOpenAIFinishReason(choice.finish_reason),
1058
+ finishReason: mapOpenAIFinishReason({
1059
+ finishReason: choice.finish_reason,
1060
+ hasRefusal
1061
+ }),
1003
1062
  usage: {
1004
- inputTokens: (_i = (_h = response.usage) == null ? void 0 : _h.prompt_tokens) != null ? _i : void 0,
1005
- outputTokens: (_k = (_j = response.usage) == null ? void 0 : _j.completion_tokens) != null ? _k : void 0,
1006
- totalTokens: (_m = (_l = response.usage) == null ? void 0 : _l.total_tokens) != null ? _m : void 0,
1007
- reasoningTokens: (_n = completionTokenDetails == null ? void 0 : completionTokenDetails.reasoning_tokens) != null ? _n : void 0,
1008
- cachedInputTokens: (_o = promptTokenDetails == null ? void 0 : promptTokenDetails.cached_tokens) != null ? _o : void 0
1063
+ inputTokens: (_j = (_i = response.usage) == null ? void 0 : _i.prompt_tokens) != null ? _j : void 0,
1064
+ outputTokens: (_l = (_k = response.usage) == null ? void 0 : _k.completion_tokens) != null ? _l : void 0,
1065
+ totalTokens: (_n = (_m = response.usage) == null ? void 0 : _m.total_tokens) != null ? _n : void 0,
1066
+ reasoningTokens: (_o = completionTokenDetails == null ? void 0 : completionTokenDetails.reasoning_tokens) != null ? _o : void 0,
1067
+ cachedInputTokens: (_p = promptTokenDetails == null ? void 0 : promptTokenDetails.cached_tokens) != null ? _p : void 0
1009
1068
  },
1010
1069
  request: { body },
1011
1070
  response: {
@@ -1049,6 +1108,10 @@ var OpenAIChatLanguageModel = class {
1049
1108
  };
1050
1109
  let metadataExtracted = false;
1051
1110
  let isActiveText = false;
1111
+ let hasRefusal = false;
1112
+ let rawFinishReason = void 0;
1113
+ let hasLogprobs = false;
1114
+ const streamedLogprobs = [];
1052
1115
  const providerMetadata = { openai: {} };
1053
1116
  return {
1054
1117
  stream: response.pipeThrough(
@@ -1061,18 +1124,20 @@ var OpenAIChatLanguageModel = class {
1061
1124
  controller.enqueue({ type: "stream-start", warnings });
1062
1125
  },
1063
1126
  transform(chunk, controller) {
1064
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
1127
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
1065
1128
  if (options.includeRawChunks) {
1066
1129
  controller.enqueue({ type: "raw", rawValue: chunk.rawValue });
1067
1130
  }
1068
1131
  if (!chunk.success) {
1069
1132
  finishReason = "error";
1133
+ rawFinishReason = void 0;
1070
1134
  controller.enqueue({ type: "error", error: chunk.error });
1071
1135
  return;
1072
1136
  }
1073
1137
  const value = chunk.value;
1074
1138
  if ("error" in value) {
1075
1139
  finishReason = "error";
1140
+ rawFinishReason = void 0;
1076
1141
  controller.enqueue({ type: "error", error: value.error });
1077
1142
  return;
1078
1143
  }
@@ -1106,16 +1171,35 @@ var OpenAIChatLanguageModel = class {
1106
1171
  }
1107
1172
  const choice = value.choices[0];
1108
1173
  if ((choice == null ? void 0 : choice.finish_reason) != null) {
1109
- finishReason = mapOpenAIFinishReason(choice.finish_reason);
1174
+ rawFinishReason = choice.finish_reason;
1110
1175
  }
1111
- if (((_m = choice == null ? void 0 : choice.logprobs) == null ? void 0 : _m.content) != null) {
1112
- providerMetadata.openai.logprobs = choice.logprobs.content;
1176
+ if ((choice == null ? void 0 : choice.logprobs) != null) {
1177
+ const contentLogprobs = choice.logprobs.content;
1178
+ const refusalLogprobs = choice.logprobs.refusal;
1179
+ if (contentLogprobs != null || refusalLogprobs != null) {
1180
+ hasLogprobs = true;
1181
+ streamedLogprobs.push(
1182
+ ...contentLogprobs != null ? contentLogprobs : [],
1183
+ ...refusalLogprobs != null ? refusalLogprobs : []
1184
+ );
1185
+ }
1113
1186
  }
1114
1187
  if ((choice == null ? void 0 : choice.delta) == null) {
1115
1188
  return;
1116
1189
  }
1117
1190
  const delta = choice.delta;
1118
- if (delta.content != null) {
1191
+ const textDeltas = [];
1192
+ if (delta.content != null && delta.content.length > 0) {
1193
+ textDeltas.push(delta.content);
1194
+ }
1195
+ if (delta.refusal != null && delta.refusal.length > 0) {
1196
+ hasRefusal = true;
1197
+ textDeltas.push(delta.refusal);
1198
+ }
1199
+ if (textDeltas.length === 0 && delta.content === "") {
1200
+ textDeltas.push(delta.content);
1201
+ }
1202
+ for (const textDelta of textDeltas) {
1119
1203
  if (!isActiveText) {
1120
1204
  controller.enqueue({ type: "text-start", id: "0" });
1121
1205
  isActiveText = true;
@@ -1123,7 +1207,7 @@ var OpenAIChatLanguageModel = class {
1123
1207
  controller.enqueue({
1124
1208
  type: "text-delta",
1125
1209
  id: "0",
1126
- delta: delta.content
1210
+ delta: textDelta
1127
1211
  });
1128
1212
  }
1129
1213
  if (delta.tool_calls != null) {
@@ -1148,6 +1232,15 @@ var OpenAIChatLanguageModel = class {
1148
1232
  controller.enqueue({ type: "text-end", id: "0" });
1149
1233
  }
1150
1234
  toolCallTracker.flush();
1235
+ if (rawFinishReason != null) {
1236
+ finishReason = mapOpenAIFinishReason({
1237
+ finishReason: rawFinishReason,
1238
+ hasRefusal
1239
+ });
1240
+ }
1241
+ if (hasLogprobs) {
1242
+ providerMetadata.openai.logprobs = streamedLogprobs;
1243
+ }
1151
1244
  controller.enqueue({
1152
1245
  type: "finish",
1153
1246
  finishReason,
@@ -2764,7 +2857,7 @@ async function convertToOpenAIResponsesInput({
2764
2857
  type: "function_call",
2765
2858
  call_id: part.toolCallId,
2766
2859
  name: part.toolName,
2767
- arguments: JSON.stringify(part.input),
2860
+ arguments: serializeToolCallArguments2(part.input),
2768
2861
  ...isAsync != null && { async: isAsync },
2769
2862
  id: canUseItemId ? id : void 0
2770
2863
  });
@@ -2826,7 +2919,7 @@ async function convertToOpenAIResponsesInput({
2826
2919
  } else if (reasoningMessage !== void 0) {
2827
2920
  warnings.push({
2828
2921
  type: "other",
2829
- message: `Cannot append empty reasoning part to existing reasoning sequence. Skipping reasoning part: ${JSON.stringify(part)}.`
2922
+ message: `Cannot append empty reasoning part to existing reasoning sequence. Skipping reasoning part: ${(0, import_provider_utils22.stringifyWithBigIntAndCycles)(part)}.`
2830
2923
  });
2831
2924
  }
2832
2925
  if (reasoningMessage === void 0) {
@@ -2847,7 +2940,7 @@ async function convertToOpenAIResponsesInput({
2847
2940
  } else {
2848
2941
  warnings.push({
2849
2942
  type: "other",
2850
- message: `Non-OpenAI reasoning parts are not supported. Skipping reasoning part: ${JSON.stringify(part)}.`
2943
+ message: `Non-OpenAI reasoning parts are not supported. Skipping reasoning part: ${(0, import_provider_utils22.stringifyWithBigIntAndCycles)(part)}.`
2851
2944
  });
2852
2945
  }
2853
2946
  break;
@@ -2888,10 +2981,10 @@ async function convertToOpenAIResponsesInput({
2888
2981
  break;
2889
2982
  case "json":
2890
2983
  case "error-json":
2891
- contentValue = promptCacheBreakpoint == null ? JSON.stringify(output.value) : [
2984
+ contentValue = promptCacheBreakpoint == null ? (0, import_provider_utils22.stringifyWithBigIntAndCycles)(output.value) : [
2892
2985
  {
2893
2986
  type: "input_text",
2894
- text: JSON.stringify(output.value),
2987
+ text: (0, import_provider_utils22.stringifyWithBigIntAndCycles)(output.value),
2895
2988
  prompt_cache_breakpoint: promptCacheBreakpoint
2896
2989
  }
2897
2990
  ];
@@ -2964,16 +3057,29 @@ var openaiResponsesReasoningProviderOptionsSchema = (0, import_provider_utils22.
2964
3057
  })
2965
3058
  )
2966
3059
  );
3060
+ function serializeToolCallArguments2(input) {
3061
+ if (typeof input === "string") {
3062
+ try {
3063
+ (0, import_provider_utils22.secureJsonParse)(input);
3064
+ return input;
3065
+ } catch (e) {
3066
+ return (0, import_provider_utils22.stringifyWithBigIntAndCycles)(input);
3067
+ }
3068
+ }
3069
+ return (0, import_provider_utils22.stringifyWithBigIntAndCycles)(input === void 0 ? {} : input);
3070
+ }
2967
3071
 
2968
3072
  // src/responses/map-openai-responses-finish-reason.ts
2969
3073
  function mapOpenAIResponseFinishReason({
2970
3074
  finishReason,
2971
- hasFunctionCall
3075
+ hasFunctionCall,
3076
+ hasRefusal = false
2972
3077
  }) {
2973
3078
  switch (finishReason) {
2974
3079
  case void 0:
2975
3080
  case null:
2976
- return hasFunctionCall ? "tool-calls" : "stop";
3081
+ if (hasFunctionCall) return "tool-calls";
3082
+ return hasRefusal ? "content-filter" : "stop";
2977
3083
  case "max_output_tokens":
2978
3084
  return "length";
2979
3085
  case "content_filter":
@@ -3006,6 +3112,20 @@ var openaiResponsesChunkSchema = (0, import_provider_utils23.lazyValidator)(
3006
3112
  })
3007
3113
  ).nullish()
3008
3114
  }),
3115
+ import_v418.z.object({
3116
+ type: import_v418.z.literal("response.refusal.delta"),
3117
+ item_id: import_v418.z.string(),
3118
+ output_index: import_v418.z.number().nullish(),
3119
+ content_index: import_v418.z.number().nullish(),
3120
+ delta: import_v418.z.string()
3121
+ }),
3122
+ import_v418.z.object({
3123
+ type: import_v418.z.literal("response.refusal.done"),
3124
+ item_id: import_v418.z.string(),
3125
+ output_index: import_v418.z.number().nullish(),
3126
+ content_index: import_v418.z.number().nullish(),
3127
+ refusal: import_v418.z.string()
3128
+ }),
3009
3129
  import_v418.z.object({
3010
3130
  type: import_v418.z.enum(["response.completed", "response.incomplete"]),
3011
3131
  response: import_v418.z.object({
@@ -3292,57 +3412,64 @@ var openaiResponsesResponseSchema = (0, import_provider_utils23.lazyValidator)(
3292
3412
  role: import_v418.z.literal("assistant"),
3293
3413
  id: import_v418.z.string(),
3294
3414
  phase: import_v418.z.enum(["commentary", "final_answer"]).nullish(),
3415
+ // the API returns either text or a refusal as content parts:
3295
3416
  content: import_v418.z.array(
3296
- import_v418.z.object({
3297
- type: import_v418.z.literal("output_text"),
3298
- text: import_v418.z.string(),
3299
- logprobs: import_v418.z.array(
3300
- import_v418.z.object({
3301
- token: import_v418.z.string(),
3302
- logprob: import_v418.z.number(),
3303
- top_logprobs: import_v418.z.array(
3304
- import_v418.z.object({
3305
- token: import_v418.z.string(),
3306
- logprob: import_v418.z.number()
3307
- })
3308
- )
3309
- })
3310
- ).nullish(),
3311
- annotations: import_v418.z.array(
3312
- import_v418.z.discriminatedUnion("type", [
3313
- import_v418.z.object({
3314
- type: import_v418.z.literal("url_citation"),
3315
- start_index: import_v418.z.number(),
3316
- end_index: import_v418.z.number(),
3317
- url: import_v418.z.string(),
3318
- title: import_v418.z.string()
3319
- }),
3320
- import_v418.z.object({
3321
- type: import_v418.z.literal("file_citation"),
3322
- file_id: import_v418.z.string(),
3323
- filename: import_v418.z.string().nullish(),
3324
- index: import_v418.z.number().nullish(),
3325
- start_index: import_v418.z.number().nullish(),
3326
- end_index: import_v418.z.number().nullish(),
3327
- quote: import_v418.z.string().nullish()
3328
- }),
3329
- import_v418.z.object({
3330
- type: import_v418.z.literal("container_file_citation"),
3331
- container_id: import_v418.z.string(),
3332
- file_id: import_v418.z.string(),
3333
- filename: import_v418.z.string().nullish(),
3334
- start_index: import_v418.z.number().nullish(),
3335
- end_index: import_v418.z.number().nullish(),
3336
- index: import_v418.z.number().nullish()
3337
- }),
3417
+ import_v418.z.discriminatedUnion("type", [
3418
+ import_v418.z.object({
3419
+ type: import_v418.z.literal("output_text"),
3420
+ text: import_v418.z.string(),
3421
+ logprobs: import_v418.z.array(
3338
3422
  import_v418.z.object({
3339
- type: import_v418.z.literal("file_path"),
3340
- file_id: import_v418.z.string(),
3341
- index: import_v418.z.number().nullish()
3423
+ token: import_v418.z.string(),
3424
+ logprob: import_v418.z.number(),
3425
+ top_logprobs: import_v418.z.array(
3426
+ import_v418.z.object({
3427
+ token: import_v418.z.string(),
3428
+ logprob: import_v418.z.number()
3429
+ })
3430
+ )
3342
3431
  })
3343
- ])
3344
- )
3345
- })
3432
+ ).nullish(),
3433
+ annotations: import_v418.z.array(
3434
+ import_v418.z.discriminatedUnion("type", [
3435
+ import_v418.z.object({
3436
+ type: import_v418.z.literal("url_citation"),
3437
+ start_index: import_v418.z.number(),
3438
+ end_index: import_v418.z.number(),
3439
+ url: import_v418.z.string(),
3440
+ title: import_v418.z.string()
3441
+ }),
3442
+ import_v418.z.object({
3443
+ type: import_v418.z.literal("file_citation"),
3444
+ file_id: import_v418.z.string(),
3445
+ filename: import_v418.z.string().nullish(),
3446
+ index: import_v418.z.number().nullish(),
3447
+ start_index: import_v418.z.number().nullish(),
3448
+ end_index: import_v418.z.number().nullish(),
3449
+ quote: import_v418.z.string().nullish()
3450
+ }),
3451
+ import_v418.z.object({
3452
+ type: import_v418.z.literal("container_file_citation"),
3453
+ container_id: import_v418.z.string(),
3454
+ file_id: import_v418.z.string(),
3455
+ filename: import_v418.z.string().nullish(),
3456
+ start_index: import_v418.z.number().nullish(),
3457
+ end_index: import_v418.z.number().nullish(),
3458
+ index: import_v418.z.number().nullish()
3459
+ }),
3460
+ import_v418.z.object({
3461
+ type: import_v418.z.literal("file_path"),
3462
+ file_id: import_v418.z.string(),
3463
+ index: import_v418.z.number().nullish()
3464
+ })
3465
+ ])
3466
+ )
3467
+ }),
3468
+ import_v418.z.object({
3469
+ type: import_v418.z.literal("refusal"),
3470
+ refusal: import_v418.z.string()
3471
+ })
3472
+ ])
3346
3473
  )
3347
3474
  }),
3348
3475
  import_v418.z.object({
@@ -4004,6 +4131,7 @@ var OpenAIResponsesLanguageModel = class {
4004
4131
  const content = [];
4005
4132
  const logprobs = [];
4006
4133
  let hasFunctionCall = false;
4134
+ let hasRefusal = false;
4007
4135
  for (const part of response.output) {
4008
4136
  switch (part.type) {
4009
4137
  case "reasoning": {
@@ -4061,6 +4189,20 @@ var OpenAIResponsesLanguageModel = class {
4061
4189
  }
4062
4190
  case "message": {
4063
4191
  for (const contentPart of part.content) {
4192
+ if (contentPart.type === "refusal") {
4193
+ hasRefusal = true;
4194
+ content.push({
4195
+ type: "text",
4196
+ text: contentPart.refusal,
4197
+ providerMetadata: {
4198
+ [providerKey]: {
4199
+ itemId: part.id,
4200
+ ...part.phase != null && { phase: part.phase }
4201
+ }
4202
+ }
4203
+ });
4204
+ continue;
4205
+ }
4064
4206
  if (((_c = (_b = options.providerOptions) == null ? void 0 : _b.openai) == null ? void 0 : _c.logprobs) && contentPart.logprobs) {
4065
4207
  logprobs.push(contentPart.logprobs);
4066
4208
  }
@@ -4261,7 +4403,8 @@ var OpenAIResponsesLanguageModel = class {
4261
4403
  content,
4262
4404
  finishReason: mapOpenAIResponseFinishReason({
4263
4405
  finishReason: (_y = response.incomplete_details) == null ? void 0 : _y.reason,
4264
- hasFunctionCall
4406
+ hasFunctionCall,
4407
+ hasRefusal
4265
4408
  }),
4266
4409
  usage: {
4267
4410
  inputTokens: usage.input_tokens,
@@ -4320,6 +4463,7 @@ var OpenAIResponsesLanguageModel = class {
4320
4463
  const ongoingAnnotations = [];
4321
4464
  let activeMessagePhase;
4322
4465
  let hasFunctionCall = false;
4466
+ let hasRefusal = false;
4323
4467
  const activeReasoning = {};
4324
4468
  let serviceTier;
4325
4469
  let reasoningContext;
@@ -4661,6 +4805,15 @@ var OpenAIResponsesLanguageModel = class {
4661
4805
  if (((_h = (_g = options.providerOptions) == null ? void 0 : _g.openai) == null ? void 0 : _h.logprobs) && value.logprobs) {
4662
4806
  logprobs.push(value.logprobs);
4663
4807
  }
4808
+ } else if (isRefusalDeltaChunk(value)) {
4809
+ hasRefusal = true;
4810
+ controller.enqueue({
4811
+ type: "text-delta",
4812
+ id: value.item_id,
4813
+ delta: value.delta
4814
+ });
4815
+ } else if (isRefusalDoneChunk(value)) {
4816
+ hasRefusal = true;
4664
4817
  } else if (value.type === "response.reasoning_summary_part.added") {
4665
4818
  if (value.summary_index > 0) {
4666
4819
  const activeReasoningPart = activeReasoning[value.item_id];
@@ -4717,7 +4870,8 @@ var OpenAIResponsesLanguageModel = class {
4717
4870
  } else if (isResponseFinishedChunk(value)) {
4718
4871
  finishReason = mapOpenAIResponseFinishReason({
4719
4872
  finishReason: (_k = value.response.incomplete_details) == null ? void 0 : _k.reason,
4720
- hasFunctionCall
4873
+ hasFunctionCall,
4874
+ hasRefusal
4721
4875
  });
4722
4876
  usage.inputTokens = value.response.usage.input_tokens;
4723
4877
  usage.outputTokens = value.response.usage.output_tokens;
@@ -4794,6 +4948,12 @@ var OpenAIResponsesLanguageModel = class {
4794
4948
  };
4795
4949
  }
4796
4950
  };
4951
+ function isRefusalDeltaChunk(chunk) {
4952
+ return chunk.type === "response.refusal.delta";
4953
+ }
4954
+ function isRefusalDoneChunk(chunk) {
4955
+ return chunk.type === "response.refusal.done";
4956
+ }
4797
4957
  function isTextDeltaChunk(chunk) {
4798
4958
  return chunk.type === "response.output_text.delta";
4799
4959
  }
@@ -5045,6 +5205,16 @@ var openAITranscriptionProviderOptions = (0, import_provider_utils29.lazyValidat
5045
5205
  * The language of the input audio in ISO-639-1 format.
5046
5206
  */
5047
5207
  language: import_v421.z.string().optional(),
5208
+ /**
5209
+ * Expected languages for REST transcription, e.g. with gpt-transcribe.
5210
+ * Use this instead of language. The API validates model support.
5211
+ */
5212
+ languages: import_v421.z.array(import_v421.z.string()).optional(),
5213
+ /**
5214
+ * Vocabulary hints for REST transcription, e.g. names or technical terms.
5215
+ * The API validates model support.
5216
+ */
5217
+ keywords: import_v421.z.array(import_v421.z.string()).optional(),
5048
5218
  /**
5049
5219
  * An optional text to guide the model's style or continue a previous audio segment.
5050
5220
  */
@@ -5156,6 +5326,8 @@ var OpenAITranscriptionModel = class {
5156
5326
  const transcriptionModelOptions = {
5157
5327
  include: openAIOptions.include,
5158
5328
  language: openAIOptions.language,
5329
+ languages: openAIOptions.languages,
5330
+ keywords: openAIOptions.keywords,
5159
5331
  prompt: openAIOptions.prompt,
5160
5332
  // https://platform.openai.com/docs/api-reference/audio/createTranscription#audio_createtranscription-response_format
5161
5333
  // prefer verbose_json to get segments for models that support it
@@ -5232,7 +5404,7 @@ var OpenAITranscriptionModel = class {
5232
5404
  };
5233
5405
 
5234
5406
  // src/version.ts
5235
- var VERSION = true ? "2.0.139" : "0.0.0-test";
5407
+ var VERSION = true ? "2.0.141" : "0.0.0-test";
5236
5408
 
5237
5409
  // src/openai-provider.ts
5238
5410
  function createOpenAI(options = {}) {