@ai-sdk/openai 4.0.101 → 4.0.103

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.
@@ -1955,6 +1955,12 @@ const result = await generateText({
1955
1955
  });
1956
1956
  ```
1957
1957
 
1958
+ For non-streaming JSON output with `generateText`, when a response contains
1959
+ messages marked with `phase: 'final_answer'`, the SDK parses only the last such
1960
+ message into `result.output`. This prevents commentary or repeated final answers
1961
+ from being joined into invalid JSON. The returned `text`, `content`, response
1962
+ messages, and token usage still include the complete response as before.
1963
+
1958
1964
  #### Typed providerMetadata in Text Parts
1959
1965
 
1960
1966
  When using the OpenAI Responses API, the SDK attaches OpenAI-specific metadata to output parts via `providerMetadata`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "4.0.101",
3
+ "version": "4.0.103",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -35,8 +35,8 @@
35
35
  }
36
36
  },
37
37
  "dependencies": {
38
- "@ai-sdk/provider": "4.0.33",
39
- "@ai-sdk/provider-utils": "5.0.67"
38
+ "@ai-sdk/provider": "4.0.34",
39
+ "@ai-sdk/provider-utils": "5.0.69"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@ai-sdk/test-server": "2.0.4",
@@ -28,7 +28,7 @@ export function convertToOpenAICompletionPrompt({
28
28
  switch (role) {
29
29
  case 'system': {
30
30
  throw new InvalidPromptError({
31
- message: 'Unexpected system message in prompt: ${content}',
31
+ message: `Unexpected system message in prompt: ${content}`,
32
32
  prompt,
33
33
  });
34
34
  }
@@ -17,5 +17,6 @@ export * from '../tool/code-interpreter';
17
17
  export * from '../tool/file-search';
18
18
  export * from '../tool/image-generation';
19
19
  export * from '../tool/programmatic-tool-calling';
20
+ export * from '../tool/tool-search';
20
21
  export * from '../tool/web-search';
21
22
  export * from '../tool/web-search-preview';
@@ -413,6 +413,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
413
413
  customProviderToolNames,
414
414
  outputSchemaToolNames,
415
415
  supportsAsyncToolCalling: modelCapabilities.supportsAsyncToolCalling,
416
+ providerOptionsName,
416
417
  });
417
418
 
418
419
  const configurationUpdateUnsupportedReason =
@@ -926,6 +927,8 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
926
927
  let hasFunctionCall = false;
927
928
  const hostedToolSearchCallIds: string[] = [];
928
929
 
930
+ let structuredOutputText: string | undefined;
931
+
929
932
  // map response content to content array
930
933
  for (const part of response.output) {
931
934
  switch (part.type) {
@@ -1086,6 +1089,17 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
1086
1089
  }
1087
1090
 
1088
1091
  case 'message': {
1092
+ // Parse only the last final answer for JSON output, while preserving
1093
+ // every message and its metadata in the generated content.
1094
+ if (
1095
+ options.responseFormat?.type === 'json' &&
1096
+ part.phase === 'final_answer'
1097
+ ) {
1098
+ structuredOutputText = part.content
1099
+ .map(contentPart => contentPart.text)
1100
+ .join('');
1101
+ }
1102
+
1089
1103
  for (const contentPart of part.content) {
1090
1104
  if (
1091
1105
  options.providerOptions?.[providerOptionsName]?.logprobs &&
@@ -1516,6 +1530,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
1516
1530
 
1517
1531
  return {
1518
1532
  content,
1533
+ ...(structuredOutputText !== undefined && { structuredOutputText }),
1519
1534
  finishReason: {
1520
1535
  unified: mapOpenAIResponseFinishReason({
1521
1536
  finishReason: response.incomplete_details?.reason,
@@ -61,6 +61,7 @@ export async function prepareResponsesTools({
61
61
  customProviderToolNames,
62
62
  outputSchemaToolNames,
63
63
  supportsAsyncToolCalling = true,
64
+ providerOptionsName = 'openai',
64
65
  }: {
65
66
  tools: LanguageModelV4CallOptions['tools'];
66
67
  toolChoice: LanguageModelV4CallOptions['toolChoice'] | undefined;
@@ -72,6 +73,7 @@ export async function prepareResponsesTools({
72
73
  customProviderToolNames?: Set<string>;
73
74
  outputSchemaToolNames?: Set<string>;
74
75
  supportsAsyncToolCalling?: boolean;
76
+ providerOptionsName?: string;
75
77
  }): Promise<{
76
78
  tools?: Array<OpenAIResponsesTool>;
77
79
  toolChoice?:
@@ -145,9 +147,8 @@ export async function prepareResponsesTools({
145
147
  for (const tool of tools) {
146
148
  switch (tool.type) {
147
149
  case 'function': {
148
- const openaiOptions = tool.providerOptions?.openai as
149
- | OpenAIToolOptions
150
- | undefined;
150
+ const openaiOptions = (tool.providerOptions?.[providerOptionsName] ??
151
+ tool.providerOptions?.openai) as OpenAIToolOptions | undefined;
151
152
  if (openaiOptions?.outputSchema != null) {
152
153
  outputSchemaToolNames?.add(tool.name);
153
154
  }