@ai-sdk/openai 4.0.53 → 4.0.54

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,12 @@
1
1
  # @ai-sdk/openai
2
2
 
3
+ ## 4.0.54
4
+
5
+ ### Patch Changes
6
+
7
+ - f6fac50: fix(openai): handle null usage in responses
8
+ - e07b577: feat: add tool calling support to batch
9
+
3
10
  ## 4.0.53
4
11
 
5
12
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -252,7 +252,10 @@ declare const openaiResponsesChunkSchema: _ai_sdk_provider_utils.LazySchema<{
252
252
  } | {
253
253
  type: "response.completed" | "response.incomplete";
254
254
  response: {
255
- usage: {
255
+ incomplete_details?: {
256
+ reason: string;
257
+ } | null | undefined;
258
+ usage?: {
256
259
  input_tokens: number;
257
260
  output_tokens: number;
258
261
  input_tokens_details?: {
@@ -265,9 +268,6 @@ declare const openaiResponsesChunkSchema: _ai_sdk_provider_utils.LazySchema<{
265
268
  reasoning_tokens?: number | null | undefined;
266
269
  orchestration_output_tokens?: number | null | undefined;
267
270
  } | null | undefined;
268
- };
269
- incomplete_details?: {
270
- reason: string;
271
271
  } | null | undefined;
272
272
  reasoning?: {
273
273
  context?: string | null | undefined;
package/dist/index.js CHANGED
@@ -3669,7 +3669,7 @@ var openaiResponsesChunkSchema = lazySchema24(
3669
3669
  reasoning_tokens: z25.number().nullish(),
3670
3670
  orchestration_output_tokens: z25.number().nullish()
3671
3671
  }).nullish()
3672
- }),
3672
+ }).nullish(),
3673
3673
  reasoning: z25.object({
3674
3674
  context: z25.string().nullish()
3675
3675
  }).nullish(),
@@ -4501,7 +4501,7 @@ var openaiResponsesResponseSchema = lazySchema24(
4501
4501
  reasoning_tokens: z25.number().nullish(),
4502
4502
  orchestration_output_tokens: z25.number().nullish()
4503
4503
  }).nullish()
4504
- }).optional()
4504
+ }).nullish()
4505
4505
  })
4506
4506
  )
4507
4507
  );
@@ -7570,7 +7570,7 @@ var OpenAIResponsesLanguageModel = class _OpenAIResponsesLanguageModel {
7570
7570
  controller.enqueue({ type: "stream-start", warnings });
7571
7571
  },
7572
7572
  transform(chunk, controller) {
7573
- var _a3, _b2, _c2, _d2, _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, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R;
7573
+ var _a3, _b2, _c2, _d2, _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, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S;
7574
7574
  if (options.includeRawChunks) {
7575
7575
  controller.enqueue({ type: "raw", rawValue: chunk.rawValue });
7576
7576
  }
@@ -8505,15 +8505,15 @@ var OpenAIResponsesLanguageModel = class _OpenAIResponsesLanguageModel {
8505
8505
  raw: (_z = (_y = value.response.incomplete_details) == null ? void 0 : _y.reason) != null ? _z : void 0
8506
8506
  };
8507
8507
  }
8508
- usage = value.response.usage;
8508
+ usage = (_A = value.response.usage) != null ? _A : void 0;
8509
8509
  if (typeof value.response.service_tier === "string") {
8510
8510
  serviceTier = value.response.service_tier;
8511
8511
  }
8512
- if (((_A = value.response.reasoning) == null ? void 0 : _A.context) != null) {
8512
+ if (((_B = value.response.reasoning) == null ? void 0 : _B.context) != null) {
8513
8513
  reasoningContext = value.response.reasoning.context;
8514
8514
  }
8515
8515
  } else if (isResponseFailedChunk(value)) {
8516
- const incompleteReason = (_B = value.response.incomplete_details) == null ? void 0 : _B.reason;
8516
+ const incompleteReason = (_C = value.response.incomplete_details) == null ? void 0 : _C.reason;
8517
8517
  finishReason = {
8518
8518
  unified: incompleteReason ? mapOpenAIResponseFinishReason({
8519
8519
  finishReason: incompleteReason,
@@ -8521,8 +8521,8 @@ var OpenAIResponsesLanguageModel = class _OpenAIResponsesLanguageModel {
8521
8521
  }) : "error",
8522
8522
  raw: incompleteReason != null ? incompleteReason : "error"
8523
8523
  };
8524
- usage = (_C = value.response.usage) != null ? _C : void 0;
8525
- if (((_D = value.response.reasoning) == null ? void 0 : _D.context) != null) {
8524
+ usage = (_D = value.response.usage) != null ? _D : void 0;
8525
+ if (((_E = value.response.reasoning) == null ? void 0 : _E.context) != null) {
8526
8526
  reasoningContext = value.response.reasoning.context;
8527
8527
  }
8528
8528
  if (!encounteredStreamError && value.response.error != null) {
@@ -8538,7 +8538,7 @@ var OpenAIResponsesLanguageModel = class _OpenAIResponsesLanguageModel {
8538
8538
  };
8539
8539
  controller.enqueue({
8540
8540
  type: "error",
8541
- error: (_E = createOpenAIProviderStreamError(error)) != null ? _E : error
8541
+ error: (_F = createOpenAIProviderStreamError(error)) != null ? _F : error
8542
8542
  });
8543
8543
  }
8544
8544
  } else if (isResponseAnnotationAddedChunk(value)) {
@@ -8547,7 +8547,7 @@ var OpenAIResponsesLanguageModel = class _OpenAIResponsesLanguageModel {
8547
8547
  controller.enqueue({
8548
8548
  type: "source",
8549
8549
  sourceType: "url",
8550
- id: (_H = (_G = (_F = self.config).generateId) == null ? void 0 : _G.call(_F)) != null ? _H : generateId2(),
8550
+ id: (_I = (_H = (_G = self.config).generateId) == null ? void 0 : _H.call(_G)) != null ? _I : generateId2(),
8551
8551
  url: value.annotation.url,
8552
8552
  title: value.annotation.title
8553
8553
  });
@@ -8555,7 +8555,7 @@ var OpenAIResponsesLanguageModel = class _OpenAIResponsesLanguageModel {
8555
8555
  controller.enqueue({
8556
8556
  type: "source",
8557
8557
  sourceType: "document",
8558
- id: (_K = (_J = (_I = self.config).generateId) == null ? void 0 : _J.call(_I)) != null ? _K : generateId2(),
8558
+ id: (_L = (_K = (_J = self.config).generateId) == null ? void 0 : _K.call(_J)) != null ? _L : generateId2(),
8559
8559
  mediaType: "text/plain",
8560
8560
  title: value.annotation.filename,
8561
8561
  filename: value.annotation.filename,
@@ -8571,7 +8571,7 @@ var OpenAIResponsesLanguageModel = class _OpenAIResponsesLanguageModel {
8571
8571
  controller.enqueue({
8572
8572
  type: "source",
8573
8573
  sourceType: "document",
8574
- id: (_N = (_M = (_L = self.config).generateId) == null ? void 0 : _M.call(_L)) != null ? _N : generateId2(),
8574
+ id: (_O = (_N = (_M = self.config).generateId) == null ? void 0 : _N.call(_M)) != null ? _O : generateId2(),
8575
8575
  mediaType: "text/plain",
8576
8576
  title: value.annotation.filename,
8577
8577
  filename: value.annotation.filename,
@@ -8587,7 +8587,7 @@ var OpenAIResponsesLanguageModel = class _OpenAIResponsesLanguageModel {
8587
8587
  controller.enqueue({
8588
8588
  type: "source",
8589
8589
  sourceType: "document",
8590
- id: (_Q = (_P = (_O = self.config).generateId) == null ? void 0 : _P.call(_O)) != null ? _Q : generateId2(),
8590
+ id: (_R = (_Q = (_P = self.config).generateId) == null ? void 0 : _Q.call(_P)) != null ? _R : generateId2(),
8591
8591
  mediaType: "application/octet-stream",
8592
8592
  title: value.annotation.file_id,
8593
8593
  filename: value.annotation.file_id,
@@ -8605,7 +8605,7 @@ var OpenAIResponsesLanguageModel = class _OpenAIResponsesLanguageModel {
8605
8605
  finishReason = { unified: "error", raw: "error" };
8606
8606
  controller.enqueue({
8607
8607
  type: "error",
8608
- error: (_R = createOpenAIProviderStreamError(value)) != null ? _R : value
8608
+ error: (_S = createOpenAIProviderStreamError(value)) != null ? _S : value
8609
8609
  });
8610
8610
  }
8611
8611
  },
@@ -8808,7 +8808,7 @@ var OpenAIResponsesBatch = class {
8808
8808
  this.options = options;
8809
8809
  }
8810
8810
  async startBatch(options) {
8811
- var _a2, _b, _c, _d;
8811
+ var _a2, _b, _c, _d, _e;
8812
8812
  const fileParts = [];
8813
8813
  const warnings = options.webhookUrl == null ? [] : [
8814
8814
  {
@@ -8833,6 +8833,18 @@ var OpenAIResponsesBatch = class {
8833
8833
  for (const warning of preparedRequest.warnings) {
8834
8834
  warnings.push({ requestId: request.id, warning });
8835
8835
  }
8836
+ for (const tool of (_a2 = request.options.tools) != null ? _a2 : []) {
8837
+ if (tool.type === "provider" && !openAIBatchConvertibleProviderToolIds.has(tool.id)) {
8838
+ warnings.push({
8839
+ requestId: request.id,
8840
+ warning: {
8841
+ type: "unsupported",
8842
+ feature: `batch result conversion for tool "${tool.name}"`,
8843
+ details: "OpenAI may return output for this tool that AI SDK text batches cannot currently convert."
8844
+ }
8845
+ });
8846
+ }
8847
+ }
8836
8848
  }
8837
8849
  const filename = "batch.jsonl";
8838
8850
  const file = new Blob(fileParts, {
@@ -8849,7 +8861,7 @@ var OpenAIResponsesBatch = class {
8849
8861
  );
8850
8862
  const { value: uploadedFile } = await postToApi({
8851
8863
  url: this.getUrl("/files"),
8852
- headers: combineHeaders7((_b = (_a2 = this.options.config).headers) == null ? void 0 : _b.call(_a2), options.headers),
8864
+ headers: combineHeaders7((_c = (_b = this.options.config).headers) == null ? void 0 : _c.call(_b), options.headers),
8853
8865
  body: {
8854
8866
  content: formData,
8855
8867
  values: {
@@ -8874,7 +8886,7 @@ var OpenAIResponsesBatch = class {
8874
8886
  });
8875
8887
  const { value: batch } = await postJsonToApi6({
8876
8888
  url: this.getUrl("/batches"),
8877
- headers: combineHeaders7((_d = (_c = this.options.config).headers) == null ? void 0 : _d.call(_c), options.headers),
8889
+ headers: combineHeaders7((_e = (_d = this.options.config).headers) == null ? void 0 : _e.call(_d), options.headers),
8878
8890
  body: {
8879
8891
  input_file_id: uploadedFile.id,
8880
8892
  endpoint: openaiBatchEndpoint,
@@ -9015,6 +9027,13 @@ var OpenAIResponsesBatch = class {
9015
9027
  });
9016
9028
  }
9017
9029
  };
9030
+ var openAIBatchConvertibleProviderToolIds = /* @__PURE__ */ new Set([
9031
+ "openai.code_interpreter",
9032
+ "openai.custom",
9033
+ "openai.file_search",
9034
+ "openai.web_search",
9035
+ "openai.web_search_preview"
9036
+ ]);
9018
9037
  var OpenAIResponsesBatchLanguageModel = class _OpenAIResponsesBatchLanguageModel extends OpenAIResponsesLanguageModel {
9019
9038
  static [WORKFLOW_SERIALIZE6](model) {
9020
9039
  return OpenAIResponsesLanguageModel[WORKFLOW_SERIALIZE6](model);
@@ -9124,7 +9143,7 @@ async function convertOpenAIErrorResponse({
9124
9143
  };
9125
9144
  }
9126
9145
  async function convertOpenAIResponsesBatchResponse(body) {
9127
- var _a2, _b, _c, _d, _e, _f;
9146
+ var _a2, _b, _c, _d, _e, _f, _g, _h;
9128
9147
  const validation = await safeValidateTypes({
9129
9148
  value: body,
9130
9149
  schema: openaiResponsesResponseSchema
@@ -9161,6 +9180,7 @@ async function convertOpenAIResponsesBatchResponse(body) {
9161
9180
  }
9162
9181
  const content = [];
9163
9182
  const logprobs = [];
9183
+ let hasFunctionCall = false;
9164
9184
  for (const part of response.output) {
9165
9185
  switch (part.type) {
9166
9186
  case "reasoning": {
@@ -9189,14 +9209,96 @@ async function convertOpenAIResponsesBatchResponse(body) {
9189
9209
  break;
9190
9210
  }
9191
9211
  case "function_call":
9192
- case "custom_tool_call":
9193
- return {
9194
- success: false,
9195
- error: {
9196
- message: "OpenAI returned a tool call, but tool calls are not supported in AI SDK text batches.",
9197
- code: "unsupported_content"
9212
+ hasFunctionCall = true;
9213
+ content.push({
9214
+ type: "tool-call",
9215
+ toolCallId: part.call_id,
9216
+ toolName: part.name,
9217
+ input: part.arguments,
9218
+ providerMetadata: {
9219
+ openai: {
9220
+ itemId: part.id,
9221
+ ...part.namespace != null && { namespace: part.namespace },
9222
+ ...part.caller != null && {
9223
+ caller: part.caller.type === "program" ? { type: "program", callerId: part.caller.caller_id } : part.caller
9224
+ }
9225
+ }
9198
9226
  }
9199
- };
9227
+ });
9228
+ break;
9229
+ case "custom_tool_call":
9230
+ hasFunctionCall = true;
9231
+ content.push({
9232
+ type: "tool-call",
9233
+ toolCallId: part.call_id,
9234
+ toolName: part.name,
9235
+ input: JSON.stringify(part.input),
9236
+ providerMetadata: { openai: { itemId: part.id } }
9237
+ });
9238
+ break;
9239
+ case "web_search_call":
9240
+ content.push({
9241
+ type: "tool-call",
9242
+ toolCallId: part.id,
9243
+ toolName: "web_search",
9244
+ input: "{}",
9245
+ providerExecuted: true,
9246
+ dynamic: true
9247
+ });
9248
+ content.push({
9249
+ type: "tool-result",
9250
+ toolCallId: part.id,
9251
+ toolName: "web_search",
9252
+ result: mapWebSearchOutput(part.action),
9253
+ dynamic: true
9254
+ });
9255
+ break;
9256
+ case "file_search_call":
9257
+ content.push({
9258
+ type: "tool-call",
9259
+ toolCallId: part.id,
9260
+ toolName: "file_search",
9261
+ input: "{}",
9262
+ providerExecuted: true,
9263
+ dynamic: true
9264
+ });
9265
+ content.push({
9266
+ type: "tool-result",
9267
+ toolCallId: part.id,
9268
+ toolName: "file_search",
9269
+ result: {
9270
+ queries: part.queries,
9271
+ results: (_d = (_c = part.results) == null ? void 0 : _c.map((result) => ({
9272
+ attributes: result.attributes,
9273
+ fileId: result.file_id,
9274
+ filename: result.filename,
9275
+ score: result.score,
9276
+ text: result.text
9277
+ }))) != null ? _d : null
9278
+ },
9279
+ dynamic: true
9280
+ });
9281
+ break;
9282
+ case "code_interpreter_call":
9283
+ content.push({
9284
+ type: "tool-call",
9285
+ toolCallId: part.id,
9286
+ toolName: "code_interpreter",
9287
+ input: JSON.stringify({
9288
+ code: part.code,
9289
+ containerId: part.container_id
9290
+ }),
9291
+ providerExecuted: true,
9292
+ dynamic: true
9293
+ });
9294
+ content.push({
9295
+ type: "tool-result",
9296
+ toolCallId: part.id,
9297
+ toolName: "code_interpreter",
9298
+ result: { outputs: part.outputs },
9299
+ dynamic: true
9300
+ });
9301
+ break;
9200
9302
  default:
9201
9303
  return {
9202
9304
  success: false,
@@ -9212,7 +9314,7 @@ async function convertOpenAIResponsesBatchResponse(body) {
9212
9314
  responseId: response.id,
9213
9315
  ...logprobs.length > 0 ? { logprobs } : {},
9214
9316
  ...typeof response.service_tier === "string" ? { serviceTier: response.service_tier } : {},
9215
- ...((_c = response.reasoning) == null ? void 0 : _c.context) != null ? { reasoningContext: response.reasoning.context } : {}
9317
+ ...((_e = response.reasoning) == null ? void 0 : _e.context) != null ? { reasoningContext: response.reasoning.context } : {}
9216
9318
  }
9217
9319
  };
9218
9320
  return {
@@ -9221,10 +9323,10 @@ async function convertOpenAIResponsesBatchResponse(body) {
9221
9323
  content,
9222
9324
  finishReason: {
9223
9325
  unified: mapOpenAIResponseFinishReason({
9224
- finishReason: (_d = response.incomplete_details) == null ? void 0 : _d.reason,
9225
- hasFunctionCall: false
9326
+ finishReason: (_f = response.incomplete_details) == null ? void 0 : _f.reason,
9327
+ hasFunctionCall
9226
9328
  }),
9227
- raw: (_f = (_e = response.incomplete_details) == null ? void 0 : _e.reason) != null ? _f : void 0
9329
+ raw: (_h = (_g = response.incomplete_details) == null ? void 0 : _g.reason) != null ? _h : void 0
9228
9330
  },
9229
9331
  usage: convertOpenAIResponsesUsage(response.usage),
9230
9332
  response: {
@@ -10698,7 +10800,7 @@ var OpenAISkills = class {
10698
10800
  };
10699
10801
 
10700
10802
  // src/version.ts
10701
- var VERSION = true ? "4.0.53" : "0.0.0-test";
10803
+ var VERSION = true ? "4.0.54" : "0.0.0-test";
10702
10804
 
10703
10805
  // src/openai-provider.ts
10704
10806
  function createOpenAI(options = {}) {