@ai-sdk/open-responses 0.0.0-6b196531-20260710185421

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.
@@ -0,0 +1,253 @@
1
+ import {
2
+ UnsupportedFunctionalityError,
3
+ type LanguageModelV4Prompt,
4
+ type SharedV4Warning,
5
+ } from '@ai-sdk/provider';
6
+ import {
7
+ convertToBase64,
8
+ getTopLevelMediaType,
9
+ resolveFullMediaType,
10
+ } from '@ai-sdk/provider-utils';
11
+ import type {
12
+ FunctionCallItemParam,
13
+ FunctionCallOutputItemParam,
14
+ InputFileContentParam,
15
+ InputImageContentParam,
16
+ InputTextContentParam,
17
+ OpenResponsesRequestBody,
18
+ OutputTextContentParam,
19
+ RefusalContentParam,
20
+ } from './open-responses-api';
21
+
22
+ export async function convertToOpenResponsesInput({
23
+ prompt,
24
+ }: {
25
+ prompt: LanguageModelV4Prompt;
26
+ }): Promise<{
27
+ input: OpenResponsesRequestBody['input'];
28
+ instructions: string | undefined;
29
+ warnings: Array<SharedV4Warning>;
30
+ }> {
31
+ const input: OpenResponsesRequestBody['input'] = [];
32
+ const warnings: Array<SharedV4Warning> = [];
33
+ const systemMessages: string[] = [];
34
+
35
+ for (const { role, content } of prompt) {
36
+ switch (role) {
37
+ case 'system': {
38
+ systemMessages.push(content);
39
+ break;
40
+ }
41
+
42
+ case 'user': {
43
+ const userContent: Array<
44
+ InputTextContentParam | InputImageContentParam | InputFileContentParam
45
+ > = [];
46
+
47
+ for (const part of content) {
48
+ switch (part.type) {
49
+ case 'text': {
50
+ userContent.push({ type: 'input_text', text: part.text });
51
+ break;
52
+ }
53
+ case 'file': {
54
+ switch (part.data.type) {
55
+ case 'reference': {
56
+ throw new UnsupportedFunctionalityError({
57
+ functionality: 'file parts with provider references',
58
+ });
59
+ }
60
+ case 'text': {
61
+ throw new UnsupportedFunctionalityError({
62
+ functionality: 'text file parts',
63
+ });
64
+ }
65
+ case 'url':
66
+ case 'data': {
67
+ const topLevel = getTopLevelMediaType(part.mediaType);
68
+
69
+ if (topLevel === 'image') {
70
+ userContent.push({
71
+ type: 'input_image',
72
+ ...(part.data.type === 'url'
73
+ ? { image_url: part.data.url.toString() }
74
+ : {
75
+ image_url: `data:${resolveFullMediaType({ part })};base64,${convertToBase64(part.data.data)}`,
76
+ }),
77
+ });
78
+ } else if (part.data.type === 'url') {
79
+ userContent.push({
80
+ type: 'input_file',
81
+ file_url: part.data.url.toString(),
82
+ });
83
+ } else {
84
+ const fullMediaType = resolveFullMediaType({ part });
85
+ userContent.push({
86
+ type: 'input_file',
87
+ filename: part.filename ?? 'data',
88
+ file_data: `data:${fullMediaType};base64,${convertToBase64(part.data.data)}`,
89
+ });
90
+ }
91
+
92
+ break;
93
+ }
94
+ }
95
+ break;
96
+ }
97
+ }
98
+ }
99
+
100
+ input.push({ type: 'message', role: 'user', content: userContent });
101
+ break;
102
+ }
103
+
104
+ case 'assistant': {
105
+ const assistantContent: Array<
106
+ OutputTextContentParam | RefusalContentParam
107
+ > = [];
108
+ const toolCalls: Array<FunctionCallItemParam> = [];
109
+
110
+ for (const part of content) {
111
+ switch (part.type) {
112
+ case 'text': {
113
+ assistantContent.push({ type: 'output_text', text: part.text });
114
+ break;
115
+ }
116
+ case 'tool-call': {
117
+ const argumentsValue =
118
+ typeof part.input === 'string'
119
+ ? part.input
120
+ : JSON.stringify(part.input);
121
+ toolCalls.push({
122
+ type: 'function_call',
123
+ call_id: part.toolCallId,
124
+ name: part.toolName,
125
+ arguments: argumentsValue,
126
+ });
127
+ break;
128
+ }
129
+ }
130
+ }
131
+
132
+ // Push assistant message with text content if any
133
+ if (assistantContent.length > 0) {
134
+ input.push({
135
+ type: 'message',
136
+ role: 'assistant',
137
+ content: assistantContent,
138
+ });
139
+ }
140
+
141
+ // Push function calls as separate items
142
+ for (const toolCall of toolCalls) {
143
+ input.push(toolCall);
144
+ }
145
+
146
+ break;
147
+ }
148
+
149
+ case 'tool': {
150
+ for (const part of content) {
151
+ if (part.type === 'tool-result') {
152
+ const output = part.output;
153
+ let contentValue: FunctionCallOutputItemParam['output'];
154
+
155
+ switch (output.type) {
156
+ case 'text':
157
+ case 'error-text':
158
+ contentValue = output.value;
159
+ break;
160
+ case 'execution-denied':
161
+ contentValue = output.reason ?? 'Tool call execution denied.';
162
+ break;
163
+ case 'json':
164
+ case 'error-json':
165
+ contentValue = JSON.stringify(output.value);
166
+ break;
167
+ case 'content': {
168
+ const contentParts: Array<
169
+ | InputTextContentParam
170
+ | InputImageContentParam
171
+ | InputFileContentParam
172
+ > = [];
173
+ for (const item of output.value) {
174
+ switch (item.type) {
175
+ case 'text': {
176
+ contentParts.push({
177
+ type: 'input_text',
178
+ text: item.text,
179
+ });
180
+ break;
181
+ }
182
+ case 'file': {
183
+ const topLevel = getTopLevelMediaType(item.mediaType);
184
+
185
+ if (item.data.type === 'data') {
186
+ const fullMediaType = resolveFullMediaType({
187
+ part: item,
188
+ });
189
+ if (topLevel === 'image') {
190
+ contentParts.push({
191
+ type: 'input_image',
192
+ image_url: `data:${fullMediaType};base64,${convertToBase64(item.data.data)}`,
193
+ });
194
+ } else {
195
+ contentParts.push({
196
+ type: 'input_file',
197
+ filename: item.filename ?? 'data',
198
+ file_data: `data:${fullMediaType};base64,${convertToBase64(item.data.data)}`,
199
+ });
200
+ }
201
+ } else if (item.data.type === 'url') {
202
+ if (topLevel === 'image') {
203
+ contentParts.push({
204
+ type: 'input_image',
205
+ image_url: item.data.url.toString(),
206
+ });
207
+ } else {
208
+ contentParts.push({
209
+ type: 'input_file',
210
+ file_url: item.data.url.toString(),
211
+ });
212
+ }
213
+ } else {
214
+ warnings.push({
215
+ type: 'other',
216
+ message: `unsupported tool content part type: ${item.type} with data type: ${item.data.type}`,
217
+ });
218
+ }
219
+ break;
220
+ }
221
+ default: {
222
+ warnings.push({
223
+ type: 'other',
224
+ message: `unsupported tool content part type: ${(item as { type: string }).type}`,
225
+ });
226
+ break;
227
+ }
228
+ }
229
+ }
230
+ contentValue = contentParts;
231
+ break;
232
+ }
233
+ }
234
+
235
+ input.push({
236
+ type: 'function_call_output',
237
+ call_id: part.toolCallId,
238
+ output: contentValue,
239
+ });
240
+ }
241
+ }
242
+ break;
243
+ }
244
+ }
245
+ }
246
+
247
+ return {
248
+ input,
249
+ instructions:
250
+ systemMessages.length > 0 ? systemMessages.join('\n') : undefined,
251
+ warnings,
252
+ };
253
+ }
@@ -0,0 +1,21 @@
1
+ import type { LanguageModelV4FinishReason } from '@ai-sdk/provider';
2
+
3
+ export function mapOpenResponsesFinishReason({
4
+ finishReason,
5
+ hasToolCalls,
6
+ }: {
7
+ finishReason: string | null | undefined;
8
+ hasToolCalls: boolean;
9
+ }): LanguageModelV4FinishReason['unified'] {
10
+ switch (finishReason) {
11
+ case undefined:
12
+ case null:
13
+ return hasToolCalls ? 'tool-calls' : 'stop';
14
+ case 'max_output_tokens':
15
+ return 'length';
16
+ case 'content_filter':
17
+ return 'content-filter';
18
+ default:
19
+ return hasToolCalls ? 'tool-calls' : 'other';
20
+ }
21
+ }