@ai-sdk/openai 4.0.91 → 4.0.93
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 +21 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +183 -98
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +10 -1
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +236 -151
- package/dist/internal/index.js.map +1 -1
- package/docs/03-openai.mdx +19 -0
- package/package.json +3 -3
- package/src/responses/convert-to-openai-responses-input.ts +105 -1
- package/src/responses/map-openai-responses-annotation.ts +75 -0
- package/src/responses/openai-responses-api.ts +8 -0
- package/src/responses/openai-responses-language-model.ts +168 -134
- package/src/responses/openai-responses-provider-metadata.ts +4 -0
|
@@ -71,6 +71,10 @@ import {
|
|
|
71
71
|
expandParallelToolCall,
|
|
72
72
|
isUndeclaredParallelToolCall,
|
|
73
73
|
} from './expand-parallel-tool-call';
|
|
74
|
+
import {
|
|
75
|
+
mapOpenAIResponsesAnnotationSource,
|
|
76
|
+
mapOpenAIResponsesCitations,
|
|
77
|
+
} from './map-openai-responses-annotation';
|
|
74
78
|
import { mapOpenAIResponseFinishReason } from './map-openai-responses-finish-reason';
|
|
75
79
|
import {
|
|
76
80
|
openaiResponsesChunkSchema,
|
|
@@ -95,7 +99,6 @@ import type {
|
|
|
95
99
|
ResponsesCompactionProviderMetadata,
|
|
96
100
|
ResponsesProviderMetadata,
|
|
97
101
|
ResponsesReasoningProviderMetadata,
|
|
98
|
-
ResponsesSourceDocumentProviderMetadata,
|
|
99
102
|
ResponsesTextProviderMetadata,
|
|
100
103
|
ResponsesToolCallProviderMetadata,
|
|
101
104
|
} from './openai-responses-provider-metadata';
|
|
@@ -434,6 +437,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
434
437
|
passThroughUnsupportedFiles:
|
|
435
438
|
openaiOptions?.passThroughUnsupportedFiles ?? false,
|
|
436
439
|
store: openaiOptions?.store ?? true,
|
|
440
|
+
isReasoningModel,
|
|
437
441
|
hasConversation: openaiOptions?.conversation != null,
|
|
438
442
|
hasPreviousResponseId: openaiOptions?.previousResponseId != null,
|
|
439
443
|
hasLocalShellTool: hasOpenAITool('openai.local_shell'),
|
|
@@ -905,6 +909,18 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
905
909
|
options.tools?.filter(
|
|
906
910
|
(tool): tool is LanguageModelV4FunctionTool => tool.type === 'function',
|
|
907
911
|
) ?? [];
|
|
912
|
+
const hasWebSearchActionSources = response.output.some(
|
|
913
|
+
part =>
|
|
914
|
+
part.type === 'web_search_call' &&
|
|
915
|
+
part.action?.type === 'search' &&
|
|
916
|
+
part.action.sources?.some(source => source.type === 'url'),
|
|
917
|
+
);
|
|
918
|
+
|
|
919
|
+
const hasFileSearchResults = response.output.some(
|
|
920
|
+
part =>
|
|
921
|
+
part.type === 'file_search_call' && (part.results?.length ?? 0) > 0,
|
|
922
|
+
);
|
|
923
|
+
const retrievedFileIds = new Set<string>();
|
|
908
924
|
|
|
909
925
|
// flag that checks if there have been client-side tool calls (not executed by openai)
|
|
910
926
|
let hasFunctionCall = false;
|
|
@@ -1084,78 +1100,35 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
1084
1100
|
content.push({
|
|
1085
1101
|
type: 'text',
|
|
1086
1102
|
text: contentPart.text,
|
|
1103
|
+
...(contentPart.annotations.some(
|
|
1104
|
+
annotation => annotation.type !== 'file_path',
|
|
1105
|
+
) && {
|
|
1106
|
+
citations: mapOpenAIResponsesCitations(
|
|
1107
|
+
contentPart.annotations,
|
|
1108
|
+
providerOptionsName,
|
|
1109
|
+
),
|
|
1110
|
+
}),
|
|
1087
1111
|
providerMetadata: {
|
|
1088
1112
|
[providerOptionsName]: providerMetadata,
|
|
1089
1113
|
},
|
|
1090
1114
|
});
|
|
1091
1115
|
|
|
1092
1116
|
for (const annotation of contentPart.annotations) {
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
});
|
|
1101
|
-
} else if (annotation.type === 'file_citation') {
|
|
1102
|
-
content.push({
|
|
1103
|
-
type: 'source',
|
|
1104
|
-
sourceType: 'document',
|
|
1105
|
-
id: this.config.generateId?.() ?? generateId(),
|
|
1106
|
-
mediaType: 'text/plain',
|
|
1107
|
-
title: annotation.filename,
|
|
1108
|
-
filename: annotation.filename,
|
|
1109
|
-
providerMetadata: {
|
|
1110
|
-
[providerOptionsName]: {
|
|
1111
|
-
type: annotation.type,
|
|
1112
|
-
fileId: annotation.file_id,
|
|
1113
|
-
index: annotation.index,
|
|
1114
|
-
} satisfies Extract<
|
|
1115
|
-
ResponsesSourceDocumentProviderMetadata,
|
|
1116
|
-
{ type: 'file_citation' }
|
|
1117
|
-
>,
|
|
1118
|
-
},
|
|
1119
|
-
});
|
|
1120
|
-
} else if (annotation.type === 'container_file_citation') {
|
|
1121
|
-
content.push({
|
|
1122
|
-
type: 'source',
|
|
1123
|
-
sourceType: 'document',
|
|
1124
|
-
id: this.config.generateId?.() ?? generateId(),
|
|
1125
|
-
mediaType: 'text/plain',
|
|
1126
|
-
title: annotation.filename,
|
|
1127
|
-
filename: annotation.filename,
|
|
1128
|
-
providerMetadata: {
|
|
1129
|
-
[providerOptionsName]: {
|
|
1130
|
-
type: annotation.type,
|
|
1131
|
-
fileId: annotation.file_id,
|
|
1132
|
-
containerId: annotation.container_id,
|
|
1133
|
-
} satisfies Extract<
|
|
1134
|
-
ResponsesSourceDocumentProviderMetadata,
|
|
1135
|
-
{ type: 'container_file_citation' }
|
|
1136
|
-
>,
|
|
1137
|
-
},
|
|
1138
|
-
});
|
|
1139
|
-
} else if (annotation.type === 'file_path') {
|
|
1140
|
-
content.push({
|
|
1141
|
-
type: 'source',
|
|
1142
|
-
sourceType: 'document',
|
|
1143
|
-
id: this.config.generateId?.() ?? generateId(),
|
|
1144
|
-
mediaType: 'application/octet-stream',
|
|
1145
|
-
title: annotation.file_id,
|
|
1146
|
-
filename: annotation.file_id,
|
|
1147
|
-
providerMetadata: {
|
|
1148
|
-
[providerOptionsName]: {
|
|
1149
|
-
type: annotation.type,
|
|
1150
|
-
fileId: annotation.file_id,
|
|
1151
|
-
index: annotation.index,
|
|
1152
|
-
} satisfies Extract<
|
|
1153
|
-
ResponsesSourceDocumentProviderMetadata,
|
|
1154
|
-
{ type: 'file_path' }
|
|
1155
|
-
>,
|
|
1156
|
-
},
|
|
1157
|
-
});
|
|
1117
|
+
// Use citation-derived sources only when retrieval data is unavailable.
|
|
1118
|
+
if (
|
|
1119
|
+
(annotation.type === 'url_citation' &&
|
|
1120
|
+
hasWebSearchActionSources) ||
|
|
1121
|
+
(annotation.type === 'file_citation' && hasFileSearchResults)
|
|
1122
|
+
) {
|
|
1123
|
+
continue;
|
|
1158
1124
|
}
|
|
1125
|
+
content.push(
|
|
1126
|
+
mapOpenAIResponsesAnnotationSource(
|
|
1127
|
+
annotation,
|
|
1128
|
+
providerOptionsName,
|
|
1129
|
+
this.config.generateId?.() ?? generateId(),
|
|
1130
|
+
),
|
|
1131
|
+
);
|
|
1159
1132
|
}
|
|
1160
1133
|
}
|
|
1161
1134
|
|
|
@@ -1288,6 +1261,19 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
1288
1261
|
: { result: mapWebSearchOutput(part.action) }),
|
|
1289
1262
|
});
|
|
1290
1263
|
|
|
1264
|
+
if (part.action?.type === 'search') {
|
|
1265
|
+
for (const source of part.action.sources ?? []) {
|
|
1266
|
+
if (source.type === 'url') {
|
|
1267
|
+
content.push({
|
|
1268
|
+
type: 'source',
|
|
1269
|
+
sourceType: 'url',
|
|
1270
|
+
id: this.config.generateId?.() ?? generateId(),
|
|
1271
|
+
url: source.url,
|
|
1272
|
+
});
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1291
1277
|
break;
|
|
1292
1278
|
}
|
|
1293
1279
|
|
|
@@ -1424,6 +1410,26 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
1424
1410
|
})) ?? null,
|
|
1425
1411
|
} satisfies InferSchema<typeof fileSearchOutputSchema>,
|
|
1426
1412
|
});
|
|
1413
|
+
for (const result of part.results ?? []) {
|
|
1414
|
+
if (retrievedFileIds.has(result.file_id)) {
|
|
1415
|
+
continue;
|
|
1416
|
+
}
|
|
1417
|
+
retrievedFileIds.add(result.file_id);
|
|
1418
|
+
content.push({
|
|
1419
|
+
type: 'source',
|
|
1420
|
+
sourceType: 'document',
|
|
1421
|
+
id: this.config.generateId?.() ?? generateId(),
|
|
1422
|
+
mediaType: 'text/plain',
|
|
1423
|
+
title: result.filename,
|
|
1424
|
+
filename: result.filename,
|
|
1425
|
+
providerMetadata: {
|
|
1426
|
+
[providerOptionsName]: {
|
|
1427
|
+
type: 'file_search',
|
|
1428
|
+
fileId: result.file_id,
|
|
1429
|
+
},
|
|
1430
|
+
},
|
|
1431
|
+
});
|
|
1432
|
+
}
|
|
1427
1433
|
break;
|
|
1428
1434
|
}
|
|
1429
1435
|
|
|
@@ -1617,12 +1623,16 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
1617
1623
|
> = {};
|
|
1618
1624
|
|
|
1619
1625
|
// set annotations in 'text-end' part providerMetadata.
|
|
1620
|
-
|
|
1626
|
+
let ongoingAnnotations: Array<
|
|
1621
1627
|
Extract<
|
|
1622
1628
|
OpenAIResponsesChunk,
|
|
1623
1629
|
{ type: 'response.output_text.annotation.added' }
|
|
1624
1630
|
>['annotation']
|
|
1625
1631
|
> = [];
|
|
1632
|
+
let hasWebSearchActionSources = false;
|
|
1633
|
+
let hasFileSearchResults = false;
|
|
1634
|
+
const retrievedFileIds = new Set<string>();
|
|
1635
|
+
const fallbackAnnotations: typeof ongoingAnnotations = [];
|
|
1626
1636
|
|
|
1627
1637
|
// track the phase of the current message being streamed
|
|
1628
1638
|
let activeMessagePhase: 'commentary' | 'final_answer' | undefined;
|
|
@@ -1730,6 +1740,14 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
1730
1740
|
id: value.item.call_id,
|
|
1731
1741
|
toolName,
|
|
1732
1742
|
});
|
|
1743
|
+
|
|
1744
|
+
// Custom tool input is a string, so stream its JSON encoding
|
|
1745
|
+
// consistently with the final tool call input.
|
|
1746
|
+
controller.enqueue({
|
|
1747
|
+
type: 'tool-input-delta',
|
|
1748
|
+
id: value.item.call_id,
|
|
1749
|
+
delta: '"',
|
|
1750
|
+
});
|
|
1733
1751
|
} else if (value.item.type === 'web_search_call') {
|
|
1734
1752
|
ongoingToolCalls[value.output_index] = {
|
|
1735
1753
|
toolName: toolNameMapping.toCustomToolName(
|
|
@@ -1894,7 +1912,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
1894
1912
|
// shell_call_output is handled in output_item.done
|
|
1895
1913
|
} else if (value.item.type === 'message') {
|
|
1896
1914
|
activeOutputItemIds[value.output_index] = value.item.id;
|
|
1897
|
-
ongoingAnnotations
|
|
1915
|
+
ongoingAnnotations = [];
|
|
1898
1916
|
activeMessagePhase = value.item.phase ?? undefined;
|
|
1899
1917
|
controller.enqueue({
|
|
1900
1918
|
type: 'text-start',
|
|
@@ -1941,6 +1959,14 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
1941
1959
|
controller.enqueue({
|
|
1942
1960
|
type: 'text-end',
|
|
1943
1961
|
id: itemId,
|
|
1962
|
+
...(ongoingAnnotations.some(
|
|
1963
|
+
annotation => annotation.type !== 'file_path',
|
|
1964
|
+
) && {
|
|
1965
|
+
citations: mapOpenAIResponsesCitations(
|
|
1966
|
+
ongoingAnnotations,
|
|
1967
|
+
providerOptionsName,
|
|
1968
|
+
),
|
|
1969
|
+
}),
|
|
1944
1970
|
providerMetadata: {
|
|
1945
1971
|
[providerOptionsName]: {
|
|
1946
1972
|
itemId,
|
|
@@ -2120,6 +2146,12 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
2120
2146
|
value.item.name,
|
|
2121
2147
|
);
|
|
2122
2148
|
|
|
2149
|
+
controller.enqueue({
|
|
2150
|
+
type: 'tool-input-delta',
|
|
2151
|
+
id: value.item.call_id,
|
|
2152
|
+
delta: '"',
|
|
2153
|
+
});
|
|
2154
|
+
|
|
2123
2155
|
controller.enqueue({
|
|
2124
2156
|
type: 'tool-input-end',
|
|
2125
2157
|
id: value.item.call_id,
|
|
@@ -2155,6 +2187,20 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
2155
2187
|
? { isError: true, result: { status: value.item.status } }
|
|
2156
2188
|
: { result: mapWebSearchOutput(value.item.action) }),
|
|
2157
2189
|
});
|
|
2190
|
+
|
|
2191
|
+
if (value.item.action?.type === 'search') {
|
|
2192
|
+
for (const source of value.item.action.sources ?? []) {
|
|
2193
|
+
if (source.type === 'url') {
|
|
2194
|
+
hasWebSearchActionSources = true;
|
|
2195
|
+
controller.enqueue({
|
|
2196
|
+
type: 'source',
|
|
2197
|
+
sourceType: 'url',
|
|
2198
|
+
id: self.config.generateId?.() ?? generateId(),
|
|
2199
|
+
url: source.url,
|
|
2200
|
+
});
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
2158
2204
|
} else if (value.item.type === 'computer_call') {
|
|
2159
2205
|
ongoingToolCalls[value.output_index] = undefined;
|
|
2160
2206
|
|
|
@@ -2227,6 +2273,27 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
2227
2273
|
})) ?? null,
|
|
2228
2274
|
} satisfies InferSchema<typeof fileSearchOutputSchema>,
|
|
2229
2275
|
});
|
|
2276
|
+
for (const result of value.item.results ?? []) {
|
|
2277
|
+
hasFileSearchResults = true;
|
|
2278
|
+
if (retrievedFileIds.has(result.file_id)) {
|
|
2279
|
+
continue;
|
|
2280
|
+
}
|
|
2281
|
+
retrievedFileIds.add(result.file_id);
|
|
2282
|
+
controller.enqueue({
|
|
2283
|
+
type: 'source',
|
|
2284
|
+
sourceType: 'document',
|
|
2285
|
+
id: self.config.generateId?.() ?? generateId(),
|
|
2286
|
+
mediaType: 'text/plain',
|
|
2287
|
+
title: result.filename,
|
|
2288
|
+
filename: result.filename,
|
|
2289
|
+
providerMetadata: {
|
|
2290
|
+
[providerOptionsName]: {
|
|
2291
|
+
type: 'file_search',
|
|
2292
|
+
fileId: result.file_id,
|
|
2293
|
+
},
|
|
2294
|
+
},
|
|
2295
|
+
});
|
|
2296
|
+
}
|
|
2230
2297
|
} else if (value.item.type === 'code_interpreter_call') {
|
|
2231
2298
|
ongoingToolCalls[value.output_index] = undefined;
|
|
2232
2299
|
|
|
@@ -2582,7 +2649,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
2582
2649
|
controller.enqueue({
|
|
2583
2650
|
type: 'tool-input-delta',
|
|
2584
2651
|
id: toolCall.toolCallId,
|
|
2585
|
-
delta: value.delta,
|
|
2652
|
+
delta: escapeJSONDelta(value.delta),
|
|
2586
2653
|
});
|
|
2587
2654
|
}
|
|
2588
2655
|
} else if (isResponseApplyPatchCallOperationDiffDeltaChunk(value)) {
|
|
@@ -2843,71 +2910,21 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
2843
2910
|
}
|
|
2844
2911
|
} else if (isResponseAnnotationAddedChunk(value)) {
|
|
2845
2912
|
ongoingAnnotations.push(value.annotation);
|
|
2846
|
-
if (
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
filename: value.annotation.filename,
|
|
2862
|
-
providerMetadata: {
|
|
2863
|
-
[providerOptionsName]: {
|
|
2864
|
-
type: value.annotation.type,
|
|
2865
|
-
fileId: value.annotation.file_id,
|
|
2866
|
-
index: value.annotation.index,
|
|
2867
|
-
} satisfies Extract<
|
|
2868
|
-
ResponsesSourceDocumentProviderMetadata,
|
|
2869
|
-
{ type: 'file_citation' }
|
|
2870
|
-
>,
|
|
2871
|
-
},
|
|
2872
|
-
});
|
|
2873
|
-
} else if (value.annotation.type === 'container_file_citation') {
|
|
2874
|
-
controller.enqueue({
|
|
2875
|
-
type: 'source',
|
|
2876
|
-
sourceType: 'document',
|
|
2877
|
-
id: self.config.generateId?.() ?? generateId(),
|
|
2878
|
-
mediaType: 'text/plain',
|
|
2879
|
-
title: value.annotation.filename,
|
|
2880
|
-
filename: value.annotation.filename,
|
|
2881
|
-
providerMetadata: {
|
|
2882
|
-
[providerOptionsName]: {
|
|
2883
|
-
type: value.annotation.type,
|
|
2884
|
-
fileId: value.annotation.file_id,
|
|
2885
|
-
containerId: value.annotation.container_id,
|
|
2886
|
-
} satisfies Extract<
|
|
2887
|
-
ResponsesSourceDocumentProviderMetadata,
|
|
2888
|
-
{ type: 'container_file_citation' }
|
|
2889
|
-
>,
|
|
2890
|
-
},
|
|
2891
|
-
});
|
|
2892
|
-
} else if (value.annotation.type === 'file_path') {
|
|
2893
|
-
controller.enqueue({
|
|
2894
|
-
type: 'source',
|
|
2895
|
-
sourceType: 'document',
|
|
2896
|
-
id: self.config.generateId?.() ?? generateId(),
|
|
2897
|
-
mediaType: 'application/octet-stream',
|
|
2898
|
-
title: value.annotation.file_id,
|
|
2899
|
-
filename: value.annotation.file_id,
|
|
2900
|
-
providerMetadata: {
|
|
2901
|
-
[providerOptionsName]: {
|
|
2902
|
-
type: value.annotation.type,
|
|
2903
|
-
fileId: value.annotation.file_id,
|
|
2904
|
-
index: value.annotation.index,
|
|
2905
|
-
} satisfies Extract<
|
|
2906
|
-
ResponsesSourceDocumentProviderMetadata,
|
|
2907
|
-
{ type: 'file_path' }
|
|
2908
|
-
>,
|
|
2909
|
-
},
|
|
2910
|
-
});
|
|
2913
|
+
if (
|
|
2914
|
+
value.annotation.type === 'url_citation' ||
|
|
2915
|
+
value.annotation.type === 'file_citation'
|
|
2916
|
+
) {
|
|
2917
|
+
// Retrieval events may arrive after the annotation. Decide the
|
|
2918
|
+
// compatibility fallback once the complete source set is known.
|
|
2919
|
+
fallbackAnnotations.push(value.annotation);
|
|
2920
|
+
} else {
|
|
2921
|
+
controller.enqueue(
|
|
2922
|
+
mapOpenAIResponsesAnnotationSource(
|
|
2923
|
+
value.annotation,
|
|
2924
|
+
providerOptionsName,
|
|
2925
|
+
self.config.generateId?.() ?? generateId(),
|
|
2926
|
+
),
|
|
2927
|
+
);
|
|
2911
2928
|
}
|
|
2912
2929
|
} else if (isErrorChunk(value)) {
|
|
2913
2930
|
encounteredStreamError = true;
|
|
@@ -2920,6 +2937,23 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
2920
2937
|
},
|
|
2921
2938
|
|
|
2922
2939
|
flush(controller) {
|
|
2940
|
+
for (const annotation of fallbackAnnotations) {
|
|
2941
|
+
if (
|
|
2942
|
+
(annotation.type === 'url_citation' &&
|
|
2943
|
+
hasWebSearchActionSources) ||
|
|
2944
|
+
(annotation.type === 'file_citation' && hasFileSearchResults)
|
|
2945
|
+
) {
|
|
2946
|
+
continue;
|
|
2947
|
+
}
|
|
2948
|
+
controller.enqueue(
|
|
2949
|
+
mapOpenAIResponsesAnnotationSource(
|
|
2950
|
+
annotation,
|
|
2951
|
+
providerOptionsName,
|
|
2952
|
+
self.config.generateId?.() ?? generateId(),
|
|
2953
|
+
),
|
|
2954
|
+
);
|
|
2955
|
+
}
|
|
2956
|
+
|
|
2923
2957
|
for (const toolCall of Object.values(ongoingToolCalls)) {
|
|
2924
2958
|
if (!toolCall?.suppressInputStreaming) {
|
|
2925
2959
|
continue;
|