@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "4.0.53",
3
+ "version": "4.0.54",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -44,7 +44,10 @@ import {
44
44
  openaiResponsesResponseSchema,
45
45
  type OpenAIResponsesLogprobs,
46
46
  } from './responses/openai-responses-api';
47
- import { OpenAIResponsesLanguageModel } from './responses/openai-responses-language-model';
47
+ import {
48
+ mapWebSearchOutput,
49
+ OpenAIResponsesLanguageModel,
50
+ } from './responses/openai-responses-language-model';
48
51
  import type { OpenAIResponsesModelId } from './responses/openai-responses-language-model-options';
49
52
  import type { ResponsesReasoningProviderMetadata } from './responses/openai-responses-provider-metadata';
50
53
 
@@ -166,6 +169,23 @@ class OpenAIResponsesBatch {
166
169
  for (const warning of preparedRequest.warnings) {
167
170
  warnings.push({ requestId: request.id, warning });
168
171
  }
172
+
173
+ for (const tool of request.options.tools ?? []) {
174
+ if (
175
+ tool.type === 'provider' &&
176
+ !openAIBatchConvertibleProviderToolIds.has(tool.id)
177
+ ) {
178
+ warnings.push({
179
+ requestId: request.id,
180
+ warning: {
181
+ type: 'unsupported',
182
+ feature: `batch result conversion for tool "${tool.name}"`,
183
+ details:
184
+ 'OpenAI may return output for this tool that AI SDK text batches cannot currently convert.',
185
+ },
186
+ });
187
+ }
188
+ }
169
189
  }
170
190
 
171
191
  const filename = 'batch.jsonl';
@@ -385,6 +405,14 @@ class OpenAIResponsesBatch {
385
405
  }
386
406
  }
387
407
 
408
+ const openAIBatchConvertibleProviderToolIds = new Set([
409
+ 'openai.code_interpreter',
410
+ 'openai.custom',
411
+ 'openai.file_search',
412
+ 'openai.web_search',
413
+ 'openai.web_search_preview',
414
+ ]);
415
+
388
416
  export class OpenAIResponsesBatchLanguageModel
389
417
  extends OpenAIResponsesLanguageModel
390
418
  implements BatchLanguageModelV4
@@ -580,6 +608,7 @@ async function convertOpenAIResponsesBatchResponse(
580
608
 
581
609
  const content: LanguageModelV4GenerateResult['content'] = [];
582
610
  const logprobs: Array<NonNullable<OpenAIResponsesLogprobs>> = [];
611
+ let hasFunctionCall = false;
583
612
 
584
613
  for (const part of response.output) {
585
614
  switch (part.type) {
@@ -615,15 +644,104 @@ async function convertOpenAIResponsesBatchResponse(
615
644
  }
616
645
 
617
646
  case 'function_call':
647
+ hasFunctionCall = true;
648
+ content.push({
649
+ type: 'tool-call',
650
+ toolCallId: part.call_id,
651
+ toolName: part.name,
652
+ input: part.arguments,
653
+ providerMetadata: {
654
+ openai: {
655
+ itemId: part.id,
656
+ ...(part.namespace != null && { namespace: part.namespace }),
657
+ ...(part.caller != null && {
658
+ caller:
659
+ part.caller.type === 'program'
660
+ ? { type: 'program', callerId: part.caller.caller_id }
661
+ : part.caller,
662
+ }),
663
+ },
664
+ },
665
+ });
666
+ break;
667
+
618
668
  case 'custom_tool_call':
619
- return {
620
- success: false,
621
- error: {
622
- message:
623
- 'OpenAI returned a tool call, but tool calls are not supported in AI SDK text batches.',
624
- code: 'unsupported_content',
669
+ hasFunctionCall = true;
670
+ content.push({
671
+ type: 'tool-call',
672
+ toolCallId: part.call_id,
673
+ toolName: part.name,
674
+ input: JSON.stringify(part.input),
675
+ providerMetadata: { openai: { itemId: part.id } },
676
+ });
677
+ break;
678
+
679
+ case 'web_search_call':
680
+ content.push({
681
+ type: 'tool-call',
682
+ toolCallId: part.id,
683
+ toolName: 'web_search',
684
+ input: '{}',
685
+ providerExecuted: true,
686
+ dynamic: true,
687
+ });
688
+ content.push({
689
+ type: 'tool-result',
690
+ toolCallId: part.id,
691
+ toolName: 'web_search',
692
+ result: mapWebSearchOutput(part.action),
693
+ dynamic: true,
694
+ });
695
+ break;
696
+
697
+ case 'file_search_call':
698
+ content.push({
699
+ type: 'tool-call',
700
+ toolCallId: part.id,
701
+ toolName: 'file_search',
702
+ input: '{}',
703
+ providerExecuted: true,
704
+ dynamic: true,
705
+ });
706
+ content.push({
707
+ type: 'tool-result',
708
+ toolCallId: part.id,
709
+ toolName: 'file_search',
710
+ result: {
711
+ queries: part.queries,
712
+ results:
713
+ part.results?.map(result => ({
714
+ attributes: result.attributes,
715
+ fileId: result.file_id,
716
+ filename: result.filename,
717
+ score: result.score,
718
+ text: result.text,
719
+ })) ?? null,
625
720
  },
626
- };
721
+ dynamic: true,
722
+ });
723
+ break;
724
+
725
+ case 'code_interpreter_call':
726
+ content.push({
727
+ type: 'tool-call',
728
+ toolCallId: part.id,
729
+ toolName: 'code_interpreter',
730
+ input: JSON.stringify({
731
+ code: part.code,
732
+ containerId: part.container_id,
733
+ }),
734
+ providerExecuted: true,
735
+ dynamic: true,
736
+ });
737
+ content.push({
738
+ type: 'tool-result',
739
+ toolCallId: part.id,
740
+ toolName: 'code_interpreter',
741
+ result: { outputs: part.outputs },
742
+ dynamic: true,
743
+ });
744
+ break;
627
745
 
628
746
  default:
629
747
  return {
@@ -658,7 +776,7 @@ async function convertOpenAIResponsesBatchResponse(
658
776
  finishReason: {
659
777
  unified: mapOpenAIResponseFinishReason({
660
778
  finishReason: response.incomplete_details?.reason,
661
- hasFunctionCall: false,
779
+ hasFunctionCall,
662
780
  }),
663
781
  raw: response.incomplete_details?.reason ?? undefined,
664
782
  },
@@ -831,24 +831,26 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
831
831
  type: z.enum(['response.completed', 'response.incomplete']),
832
832
  response: z.object({
833
833
  incomplete_details: z.object({ reason: z.string() }).nullish(),
834
- usage: z.object({
835
- input_tokens: z.number(),
836
- input_tokens_details: z
837
- .object({
838
- cached_tokens: z.number().nullish(),
839
- cache_write_tokens: z.number().nullish(),
840
- orchestration_input_tokens: z.number().nullish(),
841
- orchestration_input_cached_tokens: z.number().nullish(),
842
- })
843
- .nullish(),
844
- output_tokens: z.number(),
845
- output_tokens_details: z
846
- .object({
847
- reasoning_tokens: z.number().nullish(),
848
- orchestration_output_tokens: z.number().nullish(),
849
- })
850
- .nullish(),
851
- }),
834
+ usage: z
835
+ .object({
836
+ input_tokens: z.number(),
837
+ input_tokens_details: z
838
+ .object({
839
+ cached_tokens: z.number().nullish(),
840
+ cache_write_tokens: z.number().nullish(),
841
+ orchestration_input_tokens: z.number().nullish(),
842
+ orchestration_input_cached_tokens: z.number().nullish(),
843
+ })
844
+ .nullish(),
845
+ output_tokens: z.number(),
846
+ output_tokens_details: z
847
+ .object({
848
+ reasoning_tokens: z.number().nullish(),
849
+ orchestration_output_tokens: z.number().nullish(),
850
+ })
851
+ .nullish(),
852
+ })
853
+ .nullish(),
852
854
  reasoning: z
853
855
  .object({
854
856
  context: z.string().nullish(),
@@ -1762,7 +1764,7 @@ export const openaiResponsesResponseSchema = lazySchema(() =>
1762
1764
  })
1763
1765
  .nullish(),
1764
1766
  })
1765
- .optional(),
1767
+ .nullish(),
1766
1768
  }),
1767
1769
  ),
1768
1770
  );
@@ -2584,7 +2584,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
2584
2584
  raw: value.response.incomplete_details?.reason ?? undefined,
2585
2585
  };
2586
2586
  }
2587
- usage = value.response.usage;
2587
+ usage = value.response.usage ?? undefined;
2588
2588
  if (typeof value.response.service_tier === 'string') {
2589
2589
  serviceTier = value.response.service_tier;
2590
2590
  }
@@ -2915,7 +2915,7 @@ function isResponseOutputChunk(chunk: OpenAIResponsesChunk): boolean {
2915
2915
  );
2916
2916
  }
2917
2917
 
2918
- function mapWebSearchOutput(
2918
+ export function mapWebSearchOutput(
2919
2919
  action: OpenAIResponsesWebSearchAction | null | undefined,
2920
2920
  ): InferSchema<typeof webSearchOutputSchema> {
2921
2921
  if (action == null) {