@ai-sdk/xai 4.0.50 → 4.0.52
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 +15 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +262 -62
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/files/xai-files-api.ts +11 -0
- package/src/files/xai-files-options.ts +6 -0
- package/src/files/xai-files.ts +254 -35
- package/src/responses/xai-responses-batch.ts +51 -28
- package/src/xai-chat-language-model.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/xai",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.52",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@ai-sdk/provider": "4.0.
|
|
33
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
32
|
+
"@ai-sdk/provider": "4.0.10",
|
|
33
|
+
"@ai-sdk/provider-utils": "5.0.35"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@ai-sdk/test-server": "2.0.1",
|
|
@@ -8,9 +8,20 @@ export const xaiFilesResponseSchema = lazySchema(() =>
|
|
|
8
8
|
object: z.string().nullish(),
|
|
9
9
|
bytes: z.number().nullish(),
|
|
10
10
|
created_at: z.number().nullish(),
|
|
11
|
+
expires_at: z.number().nullish(),
|
|
11
12
|
filename: z.string().nullish(),
|
|
12
13
|
purpose: z.string().nullish(),
|
|
13
14
|
status: z.string().nullish(),
|
|
14
15
|
}),
|
|
15
16
|
),
|
|
16
17
|
);
|
|
18
|
+
|
|
19
|
+
export const xaiFileDeleteResponseSchema = lazySchema(() =>
|
|
20
|
+
zodSchema(
|
|
21
|
+
z.object({
|
|
22
|
+
id: z.string(),
|
|
23
|
+
object: z.string().nullish(),
|
|
24
|
+
deleted: z.boolean(),
|
|
25
|
+
}),
|
|
26
|
+
),
|
|
27
|
+
);
|
|
@@ -10,6 +10,12 @@ export const xaiFilesOptionsSchema = lazySchema(() =>
|
|
|
10
10
|
z.looseObject({
|
|
11
11
|
teamId: z.string().optional(),
|
|
12
12
|
filePath: z.string().optional(),
|
|
13
|
+
/**
|
|
14
|
+
* TTL in seconds measured from upload time; xAI accepts integers
|
|
15
|
+
* between 3600 (1 hour) and 2592000 (30 days) inclusive.
|
|
16
|
+
* Omit to keep the file until it is deleted.
|
|
17
|
+
*/
|
|
18
|
+
expiresAfter: z.number().int().min(3600).max(2_592_000).optional(),
|
|
13
19
|
}),
|
|
14
20
|
),
|
|
15
21
|
);
|
package/src/files/xai-files.ts
CHANGED
|
@@ -1,22 +1,40 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {
|
|
2
|
+
InvalidArgumentError,
|
|
3
|
+
type FilesV4,
|
|
4
|
+
type FilesV4DeleteFileCallOptions,
|
|
5
|
+
type FilesV4DeleteFileResult,
|
|
6
|
+
type FilesV4DownloadFileCallOptions,
|
|
7
|
+
type FilesV4DownloadFileResult,
|
|
8
|
+
type FilesV4GetFileMetadataCallOptions,
|
|
9
|
+
type FilesV4GetFileMetadataResult,
|
|
10
|
+
type FilesV4UploadFileCallOptions,
|
|
11
|
+
type FilesV4UploadFileResult,
|
|
12
|
+
type SharedV4ProviderReference,
|
|
5
13
|
} from '@ai-sdk/provider';
|
|
6
14
|
import {
|
|
7
15
|
combineHeaders,
|
|
8
16
|
convertInlineFileDataToUint8Array,
|
|
17
|
+
createBinaryStreamResponseHandler,
|
|
9
18
|
createJsonResponseHandler,
|
|
19
|
+
deleteFromApi,
|
|
20
|
+
getFromApi,
|
|
10
21
|
parseProviderOptions,
|
|
11
22
|
postFormDataToApi,
|
|
23
|
+
postMultipartStreamToApi,
|
|
12
24
|
type FetchFunction,
|
|
25
|
+
type InferSchema,
|
|
26
|
+
type MultipartStreamPart,
|
|
13
27
|
} from '@ai-sdk/provider-utils';
|
|
14
28
|
import { xaiFailedResponseHandler } from '../xai-error';
|
|
15
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
xaiFileDeleteResponseSchema,
|
|
31
|
+
xaiFilesResponseSchema,
|
|
32
|
+
} from './xai-files-api';
|
|
16
33
|
import {
|
|
17
34
|
xaiFilesOptionsSchema,
|
|
18
35
|
type XaiFilesOptions,
|
|
19
36
|
} from './xai-files-options';
|
|
37
|
+
|
|
20
38
|
interface XaiFilesConfig {
|
|
21
39
|
provider: string;
|
|
22
40
|
baseURL: string | undefined;
|
|
@@ -24,6 +42,19 @@ interface XaiFilesConfig {
|
|
|
24
42
|
fetch?: FetchFunction;
|
|
25
43
|
}
|
|
26
44
|
|
|
45
|
+
type XaiFilesResponse = InferSchema<typeof xaiFilesResponseSchema>;
|
|
46
|
+
|
|
47
|
+
function encodePathSegment(value: string): string {
|
|
48
|
+
const encodedValue = encodeURIComponent(value);
|
|
49
|
+
|
|
50
|
+
// URL parsing normalizes both literal and percent-encoded dot segments.
|
|
51
|
+
return encodedValue === '.'
|
|
52
|
+
? '%252E'
|
|
53
|
+
: encodedValue === '..'
|
|
54
|
+
? '%252E%252E'
|
|
55
|
+
: encodedValue;
|
|
56
|
+
}
|
|
57
|
+
|
|
27
58
|
export class XaiFiles implements FilesV4 {
|
|
28
59
|
readonly specificationVersion = 'v4';
|
|
29
60
|
|
|
@@ -33,62 +64,250 @@ export class XaiFiles implements FilesV4 {
|
|
|
33
64
|
|
|
34
65
|
constructor(private readonly config: XaiFilesConfig) {}
|
|
35
66
|
|
|
67
|
+
private getFileId(file: SharedV4ProviderReference): string {
|
|
68
|
+
const fileId = file.xai;
|
|
69
|
+
if (fileId == null || fileId.trim() === '') {
|
|
70
|
+
throw new InvalidArgumentError({
|
|
71
|
+
argument: 'file',
|
|
72
|
+
message: "file reference is missing an 'xai' file id.",
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return fileId;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private getHeaders(
|
|
79
|
+
headers: Record<string, string | undefined> | undefined,
|
|
80
|
+
): Record<string, string | undefined> {
|
|
81
|
+
return combineHeaders(this.config.headers(), headers);
|
|
82
|
+
}
|
|
83
|
+
|
|
36
84
|
async uploadFile({
|
|
37
85
|
data,
|
|
38
86
|
mediaType,
|
|
39
87
|
filename,
|
|
88
|
+
abortSignal,
|
|
89
|
+
headers,
|
|
40
90
|
providerOptions,
|
|
41
91
|
}: FilesV4UploadFileCallOptions): Promise<FilesV4UploadFileResult> {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
92
|
+
let xaiOptions: XaiFilesOptions | undefined;
|
|
93
|
+
try {
|
|
94
|
+
xaiOptions = (await parseProviderOptions({
|
|
95
|
+
provider: 'xai',
|
|
96
|
+
providerOptions,
|
|
97
|
+
schema: xaiFilesOptionsSchema,
|
|
98
|
+
})) as XaiFilesOptions | undefined;
|
|
99
|
+
} catch (error) {
|
|
100
|
+
// rejected before any request: release the caller's stream
|
|
101
|
+
if (data.type === 'stream') {
|
|
102
|
+
await data.stream.cancel(error).catch(() => {});
|
|
103
|
+
}
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
47
106
|
|
|
48
|
-
const
|
|
107
|
+
const requestHeaders = this.getHeaders(headers);
|
|
108
|
+
const url = `${this.config.baseURL}/files`;
|
|
49
109
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
110
|
+
let response: XaiFilesResponse;
|
|
111
|
+
|
|
112
|
+
if (data.type === 'stream') {
|
|
113
|
+
// xAI rejects uploads where expires_after arrives after the file part,
|
|
114
|
+
// so all fields precede the file.
|
|
115
|
+
const parts: Array<MultipartStreamPart> = [];
|
|
53
116
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
117
|
+
if (xaiOptions?.expiresAfter != null) {
|
|
118
|
+
parts.push({
|
|
119
|
+
type: 'field',
|
|
120
|
+
name: 'expires_after',
|
|
121
|
+
value: String(xaiOptions.expiresAfter),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (xaiOptions?.teamId != null) {
|
|
126
|
+
parts.push({
|
|
127
|
+
type: 'field',
|
|
128
|
+
name: 'team_id',
|
|
129
|
+
value: xaiOptions.teamId,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
parts.push({
|
|
134
|
+
type: 'file',
|
|
135
|
+
name: 'file',
|
|
136
|
+
filename,
|
|
137
|
+
mediaType,
|
|
138
|
+
content: data.stream,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
({ value: response } = await postMultipartStreamToApi({
|
|
142
|
+
url,
|
|
143
|
+
headers: requestHeaders,
|
|
144
|
+
parts,
|
|
145
|
+
failedResponseHandler: xaiFailedResponseHandler,
|
|
146
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
147
|
+
xaiFilesResponseSchema,
|
|
148
|
+
),
|
|
149
|
+
abortSignal,
|
|
150
|
+
fetch: this.config.fetch,
|
|
151
|
+
}));
|
|
57
152
|
} else {
|
|
58
|
-
|
|
59
|
-
}
|
|
153
|
+
const fileBytes = convertInlineFileDataToUint8Array(data);
|
|
60
154
|
|
|
61
|
-
|
|
62
|
-
|
|
155
|
+
const blob = new Blob([fileBytes], {
|
|
156
|
+
type: mediaType,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// FormData serializes in append order; expires_after must precede file.
|
|
160
|
+
const formData = new FormData();
|
|
161
|
+
|
|
162
|
+
if (xaiOptions?.expiresAfter != null) {
|
|
163
|
+
formData.append('expires_after', String(xaiOptions.expiresAfter));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (xaiOptions?.teamId != null) {
|
|
167
|
+
formData.append('team_id', xaiOptions.teamId);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (filename != null) {
|
|
171
|
+
formData.append('file', blob, filename);
|
|
172
|
+
} else {
|
|
173
|
+
formData.append('file', blob);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
({ value: response } = await postFormDataToApi({
|
|
177
|
+
url,
|
|
178
|
+
headers: requestHeaders,
|
|
179
|
+
formData,
|
|
180
|
+
failedResponseHandler: xaiFailedResponseHandler,
|
|
181
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
182
|
+
xaiFilesResponseSchema,
|
|
183
|
+
),
|
|
184
|
+
abortSignal,
|
|
185
|
+
fetch: this.config.fetch,
|
|
186
|
+
}));
|
|
63
187
|
}
|
|
64
188
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
189
|
+
return {
|
|
190
|
+
warnings: [],
|
|
191
|
+
providerReference: { xai: response.id },
|
|
192
|
+
...((response.filename ?? filename)
|
|
193
|
+
? { filename: response.filename ?? filename }
|
|
194
|
+
: {}),
|
|
195
|
+
...(mediaType != null ? { mediaType } : {}),
|
|
196
|
+
...(response.bytes != null ? { byteSize: response.bytes } : {}),
|
|
197
|
+
...(response.created_at != null
|
|
198
|
+
? { createdAt: new Date(response.created_at * 1000) }
|
|
199
|
+
: {}),
|
|
200
|
+
...(response.expires_at != null
|
|
201
|
+
? { expiresAt: new Date(response.expires_at * 1000) }
|
|
202
|
+
: {}),
|
|
203
|
+
providerMetadata: {
|
|
204
|
+
xai: this.toFileMetadata(response),
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async getFileMetadata({
|
|
210
|
+
file,
|
|
211
|
+
abortSignal,
|
|
212
|
+
headers,
|
|
213
|
+
}: FilesV4GetFileMetadataCallOptions): Promise<FilesV4GetFileMetadataResult> {
|
|
214
|
+
const fileId = this.getFileId(file);
|
|
215
|
+
|
|
216
|
+
const { value: response } = await getFromApi({
|
|
217
|
+
url: `${this.config.baseURL}/files/${encodePathSegment(fileId)}`,
|
|
218
|
+
headers: this.getHeaders(headers),
|
|
69
219
|
failedResponseHandler: xaiFailedResponseHandler,
|
|
70
220
|
successfulResponseHandler: createJsonResponseHandler(
|
|
71
221
|
xaiFilesResponseSchema,
|
|
72
222
|
),
|
|
223
|
+
abortSignal,
|
|
73
224
|
fetch: this.config.fetch,
|
|
225
|
+
validateUrl: false,
|
|
74
226
|
});
|
|
75
227
|
|
|
76
228
|
return {
|
|
77
229
|
warnings: [],
|
|
78
230
|
providerReference: { xai: response.id },
|
|
79
|
-
...(
|
|
80
|
-
|
|
231
|
+
...(response.filename != null ? { filename: response.filename } : {}),
|
|
232
|
+
...(response.bytes != null ? { byteSize: response.bytes } : {}),
|
|
233
|
+
...(response.created_at != null
|
|
234
|
+
? { createdAt: new Date(response.created_at * 1000) }
|
|
235
|
+
: {}),
|
|
236
|
+
...(response.expires_at != null
|
|
237
|
+
? { expiresAt: new Date(response.expires_at * 1000) }
|
|
81
238
|
: {}),
|
|
82
|
-
...(mediaType != null ? { mediaType } : {}),
|
|
83
239
|
providerMetadata: {
|
|
84
|
-
xai:
|
|
85
|
-
...(response.filename != null ? { filename: response.filename } : {}),
|
|
86
|
-
...(response.bytes != null ? { bytes: response.bytes } : {}),
|
|
87
|
-
...(response.created_at != null
|
|
88
|
-
? { createdAt: response.created_at }
|
|
89
|
-
: {}),
|
|
90
|
-
},
|
|
240
|
+
xai: this.toFileMetadata(response),
|
|
91
241
|
},
|
|
92
242
|
};
|
|
93
243
|
}
|
|
244
|
+
|
|
245
|
+
async downloadFile({
|
|
246
|
+
file,
|
|
247
|
+
abortSignal,
|
|
248
|
+
headers,
|
|
249
|
+
}: FilesV4DownloadFileCallOptions): Promise<FilesV4DownloadFileResult> {
|
|
250
|
+
const fileId = this.getFileId(file);
|
|
251
|
+
|
|
252
|
+
const { value: content, responseHeaders } = await getFromApi({
|
|
253
|
+
url: `${this.config.baseURL}/files/${encodePathSegment(fileId)}/content`,
|
|
254
|
+
headers: this.getHeaders(headers),
|
|
255
|
+
failedResponseHandler: xaiFailedResponseHandler,
|
|
256
|
+
successfulResponseHandler: createBinaryStreamResponseHandler(),
|
|
257
|
+
abortSignal,
|
|
258
|
+
fetch: this.config.fetch,
|
|
259
|
+
validateUrl: false,
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// media type from the content endpoint's Content-Type, without parameters
|
|
263
|
+
const mediaType = responseHeaders?.['content-type']?.split(';')[0].trim();
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
warnings: [],
|
|
267
|
+
content,
|
|
268
|
+
...(mediaType ? { mediaType } : {}),
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
async deleteFile({
|
|
273
|
+
file,
|
|
274
|
+
abortSignal,
|
|
275
|
+
headers,
|
|
276
|
+
}: FilesV4DeleteFileCallOptions): Promise<FilesV4DeleteFileResult> {
|
|
277
|
+
const fileId = this.getFileId(file);
|
|
278
|
+
|
|
279
|
+
const { value: response } = await deleteFromApi({
|
|
280
|
+
url: `${this.config.baseURL}/files/${encodePathSegment(fileId)}`,
|
|
281
|
+
headers: this.getHeaders(headers),
|
|
282
|
+
failedResponseHandler: xaiFailedResponseHandler,
|
|
283
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
284
|
+
xaiFileDeleteResponseSchema,
|
|
285
|
+
),
|
|
286
|
+
abortSignal,
|
|
287
|
+
fetch: this.config.fetch,
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
warnings: [],
|
|
292
|
+
providerReference: { xai: response.id },
|
|
293
|
+
deleted: response.deleted,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
private toFileMetadata(
|
|
298
|
+
response: XaiFilesResponse,
|
|
299
|
+
): Record<string, string | number> {
|
|
300
|
+
return {
|
|
301
|
+
...(response.filename != null ? { filename: response.filename } : {}),
|
|
302
|
+
...(response.purpose != null ? { purpose: response.purpose } : {}),
|
|
303
|
+
...(response.bytes != null ? { bytes: response.bytes } : {}),
|
|
304
|
+
...(response.created_at != null
|
|
305
|
+
? { createdAt: response.created_at }
|
|
306
|
+
: {}),
|
|
307
|
+
...(response.status != null ? { status: response.status } : {}),
|
|
308
|
+
...(response.expires_at != null
|
|
309
|
+
? { expiresAt: response.expires_at }
|
|
310
|
+
: {}),
|
|
311
|
+
};
|
|
312
|
+
}
|
|
94
313
|
}
|
|
@@ -481,8 +481,8 @@ function convertXaiChatBatchResponse(
|
|
|
481
481
|
};
|
|
482
482
|
}
|
|
483
483
|
|
|
484
|
-
const
|
|
485
|
-
if (
|
|
484
|
+
const choices = response.choices;
|
|
485
|
+
if (choices == null || choices.length === 0) {
|
|
486
486
|
return {
|
|
487
487
|
success: false,
|
|
488
488
|
error: {
|
|
@@ -492,19 +492,54 @@ function convertXaiChatBatchResponse(
|
|
|
492
492
|
};
|
|
493
493
|
}
|
|
494
494
|
|
|
495
|
-
if (choice.message.tool_calls?.length) {
|
|
496
|
-
return unsupportedXaiBatchContent('tool_calls');
|
|
497
|
-
}
|
|
498
|
-
|
|
499
495
|
const content: LanguageModelV4Content[] = [];
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
496
|
+
const providerExecutedToolCallIds = new Set(
|
|
497
|
+
choices
|
|
498
|
+
.filter(choice => choice.message.role === 'tool')
|
|
499
|
+
.flatMap(choice =>
|
|
500
|
+
(choice.message.tool_calls ?? []).map(toolCall => toolCall.id),
|
|
501
|
+
),
|
|
502
|
+
);
|
|
503
|
+
let lastAssistantChoice: (typeof choices)[number] | undefined;
|
|
504
|
+
|
|
505
|
+
for (const choice of choices) {
|
|
506
|
+
if (choice.message.role === 'tool') {
|
|
507
|
+
if (choice.message.content != null) {
|
|
508
|
+
for (const toolCall of choice.message.tool_calls ?? []) {
|
|
509
|
+
content.push({
|
|
510
|
+
type: 'tool-result',
|
|
511
|
+
toolCallId: toolCall.id,
|
|
512
|
+
toolName: toolCall.function.name,
|
|
513
|
+
result: choice.message.content,
|
|
514
|
+
dynamic: true,
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
lastAssistantChoice = choice;
|
|
522
|
+
|
|
523
|
+
if (choice.message.content) {
|
|
524
|
+
content.push({ type: 'text', text: choice.message.content });
|
|
525
|
+
}
|
|
526
|
+
if (choice.message.reasoning_content) {
|
|
527
|
+
content.push({
|
|
528
|
+
type: 'reasoning',
|
|
529
|
+
text: choice.message.reasoning_content,
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
for (const toolCall of choice.message.tool_calls ?? []) {
|
|
533
|
+
content.push({
|
|
534
|
+
type: 'tool-call',
|
|
535
|
+
toolCallId: toolCall.id,
|
|
536
|
+
toolName: toolCall.function.name,
|
|
537
|
+
input: toolCall.function.arguments,
|
|
538
|
+
...(providerExecutedToolCallIds.has(toolCall.id)
|
|
539
|
+
? { providerExecuted: true, dynamic: true }
|
|
540
|
+
: {}),
|
|
541
|
+
});
|
|
542
|
+
}
|
|
508
543
|
}
|
|
509
544
|
for (const url of response.citations ?? []) {
|
|
510
545
|
content.push({
|
|
@@ -520,8 +555,8 @@ function convertXaiChatBatchResponse(
|
|
|
520
555
|
result: {
|
|
521
556
|
content,
|
|
522
557
|
finishReason: {
|
|
523
|
-
unified: mapXaiFinishReason(
|
|
524
|
-
raw:
|
|
558
|
+
unified: mapXaiFinishReason(lastAssistantChoice?.finish_reason),
|
|
559
|
+
raw: lastAssistantChoice?.finish_reason ?? undefined,
|
|
525
560
|
},
|
|
526
561
|
usage: response.usage
|
|
527
562
|
? convertXaiChatUsage(response.usage)
|
|
@@ -544,15 +579,3 @@ function convertXaiChatBatchResponse(
|
|
|
544
579
|
},
|
|
545
580
|
};
|
|
546
581
|
}
|
|
547
|
-
|
|
548
|
-
function unsupportedXaiBatchContent(type: string): XaiBatchResponseConversion {
|
|
549
|
-
return {
|
|
550
|
-
success: false,
|
|
551
|
-
error: {
|
|
552
|
-
message:
|
|
553
|
-
`xAI returned "${type}" content, but tool content is not supported ` +
|
|
554
|
-
'in AI SDK text batches.',
|
|
555
|
-
code: 'unsupported_content',
|
|
556
|
-
},
|
|
557
|
-
};
|
|
558
|
-
}
|
|
@@ -709,7 +709,7 @@ export const xaiChatResponseSchema = z.object({
|
|
|
709
709
|
.array(
|
|
710
710
|
z.object({
|
|
711
711
|
message: z.object({
|
|
712
|
-
role: z.
|
|
712
|
+
role: z.enum(['assistant', 'tool']),
|
|
713
713
|
content: z.string().nullish(),
|
|
714
714
|
reasoning_content: z.string().nullish(),
|
|
715
715
|
tool_calls: z
|