@ai-sdk/xai 4.0.0-beta.7 → 4.0.0-beta.75
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 +660 -9
- package/README.md +2 -0
- package/dist/index.d.ts +213 -68
- package/dist/index.js +2074 -781
- package/dist/index.js.map +1 -1
- package/docs/01-xai.mdx +445 -54
- package/package.json +15 -15
- package/src/convert-to-xai-chat-messages.ts +48 -27
- package/src/convert-xai-chat-usage.ts +3 -3
- package/src/files/xai-files-api.ts +16 -0
- package/src/files/xai-files-options.ts +19 -0
- package/src/files/xai-files.ts +94 -0
- package/src/index.ts +9 -4
- package/src/map-xai-finish-reason.ts +2 -2
- package/src/realtime/index.ts +2 -0
- package/src/realtime/xai-realtime-event-mapper.ts +399 -0
- package/src/realtime/xai-realtime-model-options.ts +3 -0
- package/src/realtime/xai-realtime-model.ts +101 -0
- package/src/remove-additional-properties.ts +24 -0
- package/src/responses/convert-to-xai-responses-input.ts +100 -23
- package/src/responses/convert-xai-responses-usage.ts +3 -3
- package/src/responses/map-xai-responses-finish-reason.ts +3 -2
- package/src/responses/xai-responses-api.ts +31 -1
- package/src/responses/{xai-responses-options.ts → xai-responses-language-model-options.ts} +12 -7
- package/src/responses/xai-responses-language-model.ts +157 -60
- package/src/responses/xai-responses-prepare-tools.ts +10 -8
- package/src/tool/code-execution.ts +2 -2
- package/src/tool/file-search.ts +2 -2
- package/src/tool/mcp-server.ts +2 -2
- package/src/tool/view-image.ts +2 -2
- package/src/tool/view-x-video.ts +2 -2
- package/src/tool/web-search.ts +4 -2
- package/src/tool/x-search.ts +2 -2
- package/src/{xai-chat-options.ts → xai-chat-language-model-options.ts} +28 -13
- package/src/xai-chat-language-model.ts +65 -29
- package/src/xai-chat-prompt.ts +2 -1
- package/src/xai-error.ts +13 -3
- package/src/xai-image-model.ts +28 -11
- package/src/xai-prepare-tools.ts +9 -8
- package/src/xai-provider.ts +115 -19
- package/src/xai-speech-model-options.ts +55 -0
- package/src/xai-speech-model.ts +167 -0
- package/src/xai-transcription-model-options.ts +70 -0
- package/src/xai-transcription-model.ts +166 -0
- package/src/xai-video-model-options.ts +145 -0
- package/src/xai-video-model.ts +129 -22
- package/dist/index.d.mts +0 -377
- package/dist/index.mjs +0 -3070
- package/dist/index.mjs.map +0 -1
- package/src/xai-video-options.ts +0 -23
- /package/src/{xai-image-options.ts → xai-image-model-options.ts} +0 -0
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { LanguageModelV4FinishReason } from '@ai-sdk/provider';
|
|
2
2
|
|
|
3
3
|
export function mapXaiResponsesFinishReason(
|
|
4
4
|
finishReason: string | null | undefined,
|
|
5
|
-
):
|
|
5
|
+
): LanguageModelV4FinishReason['unified'] {
|
|
6
6
|
switch (finishReason) {
|
|
7
7
|
case 'stop':
|
|
8
8
|
case 'completed':
|
|
9
9
|
return 'stop';
|
|
10
10
|
case 'length':
|
|
11
|
+
case 'max_output_tokens':
|
|
11
12
|
return 'length';
|
|
12
13
|
case 'tool_calls':
|
|
13
14
|
case 'function_call':
|
|
@@ -26,7 +26,9 @@ export type XaiResponsesSystemMessage = {
|
|
|
26
26
|
|
|
27
27
|
export type XaiResponsesUserMessageContentPart =
|
|
28
28
|
| { type: 'input_text'; text: string }
|
|
29
|
-
| { type: 'input_image'; image_url: string }
|
|
29
|
+
| { type: 'input_image'; image_url: string }
|
|
30
|
+
| { type: 'input_file'; file_id: string }
|
|
31
|
+
| { type: 'input_file'; file_url: string };
|
|
30
32
|
|
|
31
33
|
export type XaiResponsesUserMessage = {
|
|
32
34
|
role: 'user';
|
|
@@ -77,6 +79,7 @@ export type XaiResponsesTool =
|
|
|
77
79
|
type: 'web_search';
|
|
78
80
|
allowed_domains?: string[];
|
|
79
81
|
excluded_domains?: string[];
|
|
82
|
+
enable_image_search?: boolean;
|
|
80
83
|
enable_image_understanding?: boolean;
|
|
81
84
|
}
|
|
82
85
|
| {
|
|
@@ -247,6 +250,7 @@ export const xaiResponsesUsageSchema = z.object({
|
|
|
247
250
|
.optional(),
|
|
248
251
|
num_sources_used: z.number().optional(),
|
|
249
252
|
num_server_side_tools_used: z.number().optional(),
|
|
253
|
+
cost_in_usd_ticks: z.number().nullish(),
|
|
250
254
|
});
|
|
251
255
|
|
|
252
256
|
export const xaiResponsesResponseSchema = z.object({
|
|
@@ -521,6 +525,32 @@ export const xaiResponsesChunkSchema = z.union([
|
|
|
521
525
|
output_index: z.number(),
|
|
522
526
|
output: z.string().optional(),
|
|
523
527
|
}),
|
|
528
|
+
z.object({
|
|
529
|
+
type: z.literal('response.incomplete'),
|
|
530
|
+
response: z.object({
|
|
531
|
+
incomplete_details: z.object({ reason: z.string() }).nullish(),
|
|
532
|
+
usage: xaiResponsesUsageSchema.nullish(),
|
|
533
|
+
}),
|
|
534
|
+
}),
|
|
535
|
+
z.object({
|
|
536
|
+
type: z.literal('response.failed'),
|
|
537
|
+
response: z.object({
|
|
538
|
+
error: z
|
|
539
|
+
.object({
|
|
540
|
+
code: z.string().nullish(),
|
|
541
|
+
message: z.string(),
|
|
542
|
+
})
|
|
543
|
+
.nullish(),
|
|
544
|
+
incomplete_details: z.object({ reason: z.string() }).nullish(),
|
|
545
|
+
usage: xaiResponsesUsageSchema.nullish(),
|
|
546
|
+
}),
|
|
547
|
+
}),
|
|
548
|
+
z.object({
|
|
549
|
+
type: z.literal('error'),
|
|
550
|
+
code: z.string().nullish(),
|
|
551
|
+
message: z.string(),
|
|
552
|
+
param: z.string().nullish(),
|
|
553
|
+
}),
|
|
524
554
|
z.object({
|
|
525
555
|
type: z.literal('response.done'),
|
|
526
556
|
response: xaiResponsesResponseSchema,
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod/v4';
|
|
2
2
|
|
|
3
3
|
export type XaiResponsesModelId =
|
|
4
|
-
| 'grok-4-
|
|
5
|
-
| 'grok-4-
|
|
6
|
-
| 'grok-4'
|
|
7
|
-
| 'grok-
|
|
8
|
-
| 'grok-4-fast-reasoning'
|
|
4
|
+
| 'grok-4.20-non-reasoning'
|
|
5
|
+
| 'grok-4.20-reasoning'
|
|
6
|
+
| 'grok-4.3'
|
|
7
|
+
| 'grok-latest'
|
|
9
8
|
| (string & {});
|
|
10
9
|
|
|
11
10
|
/**
|
|
@@ -14,14 +13,20 @@ export type XaiResponsesModelId =
|
|
|
14
13
|
export const xaiLanguageModelResponsesOptions = z.object({
|
|
15
14
|
/**
|
|
16
15
|
* Constrains how hard a reasoning model thinks before responding.
|
|
17
|
-
* Possible values are `
|
|
16
|
+
* Possible values are `none` (disables reasoning entirely; supported by
|
|
17
|
+
* `grok-4.3` and newer reasoning models), `low` (uses fewer reasoning
|
|
18
|
+
* tokens), `medium`, and `high` (uses more reasoning tokens).
|
|
19
|
+
*
|
|
20
|
+
* @see https://docs.x.ai/docs/guides/reasoning
|
|
18
21
|
*/
|
|
19
|
-
reasoningEffort: z.enum(['low', 'medium', 'high']).optional(),
|
|
22
|
+
reasoningEffort: z.enum(['none', 'low', 'medium', 'high']).optional(),
|
|
20
23
|
reasoningSummary: z.enum(['auto', 'concise', 'detailed']).optional(),
|
|
21
24
|
logprobs: z.boolean().optional(),
|
|
22
25
|
topLogprobs: z.number().int().min(0).max(8).optional(),
|
|
23
26
|
/**
|
|
24
27
|
* Whether to store the input message(s) and model response for later retrieval.
|
|
28
|
+
* Must be set to `false` for teams with Zero Data Retention (ZDR) enabled,
|
|
29
|
+
* otherwise the API will return an error.
|
|
25
30
|
* @default true
|
|
26
31
|
*/
|
|
27
32
|
store: z.boolean().optional(),
|
|
@@ -1,55 +1,74 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import type {
|
|
2
|
+
LanguageModelV4,
|
|
3
|
+
LanguageModelV4CallOptions,
|
|
4
|
+
LanguageModelV4Content,
|
|
5
|
+
LanguageModelV4FinishReason,
|
|
6
|
+
LanguageModelV4GenerateResult,
|
|
7
|
+
LanguageModelV4StreamPart,
|
|
8
|
+
LanguageModelV4StreamResult,
|
|
9
|
+
LanguageModelV4Usage,
|
|
10
|
+
SharedV4Warning,
|
|
11
11
|
} from '@ai-sdk/provider';
|
|
12
12
|
import {
|
|
13
13
|
combineHeaders,
|
|
14
14
|
createEventSourceResponseHandler,
|
|
15
15
|
createJsonResponseHandler,
|
|
16
|
-
|
|
16
|
+
isCustomReasoning,
|
|
17
|
+
mapReasoningToProviderEffort,
|
|
17
18
|
parseProviderOptions,
|
|
18
|
-
ParseResult,
|
|
19
19
|
postJsonToApi,
|
|
20
|
+
serializeModelOptions,
|
|
21
|
+
WORKFLOW_SERIALIZE,
|
|
22
|
+
WORKFLOW_DESERIALIZE,
|
|
23
|
+
type FetchFunction,
|
|
24
|
+
type ParseResult,
|
|
20
25
|
} from '@ai-sdk/provider-utils';
|
|
21
|
-
import { z } from 'zod/v4';
|
|
26
|
+
import type { z } from 'zod/v4';
|
|
22
27
|
import { getResponseMetadata } from '../get-response-metadata';
|
|
23
28
|
import { xaiFailedResponseHandler } from '../xai-error';
|
|
24
29
|
import { convertToXaiResponsesInput } from './convert-to-xai-responses-input';
|
|
25
30
|
import { convertXaiResponsesUsage } from './convert-xai-responses-usage';
|
|
26
31
|
import { mapXaiResponsesFinishReason } from './map-xai-responses-finish-reason';
|
|
27
32
|
import {
|
|
28
|
-
XaiResponsesIncludeOptions,
|
|
29
33
|
xaiResponsesChunkSchema,
|
|
30
34
|
xaiResponsesResponseSchema,
|
|
35
|
+
type XaiResponsesIncludeOptions,
|
|
31
36
|
} from './xai-responses-api';
|
|
32
37
|
import {
|
|
33
|
-
XaiResponsesModelId,
|
|
34
38
|
xaiLanguageModelResponsesOptions,
|
|
35
|
-
|
|
39
|
+
type XaiResponsesModelId,
|
|
40
|
+
} from './xai-responses-language-model-options';
|
|
36
41
|
import { prepareResponsesTools } from './xai-responses-prepare-tools';
|
|
37
42
|
|
|
38
43
|
type XaiResponsesConfig = {
|
|
39
44
|
provider: string;
|
|
40
45
|
baseURL: string | undefined;
|
|
41
|
-
headers
|
|
46
|
+
headers?: () => Record<string, string | undefined>;
|
|
42
47
|
generateId: () => string;
|
|
43
48
|
fetch?: FetchFunction;
|
|
44
49
|
};
|
|
45
50
|
|
|
46
|
-
export class XaiResponsesLanguageModel implements
|
|
47
|
-
readonly specificationVersion = '
|
|
51
|
+
export class XaiResponsesLanguageModel implements LanguageModelV4 {
|
|
52
|
+
readonly specificationVersion = 'v4';
|
|
48
53
|
|
|
49
54
|
readonly modelId: XaiResponsesModelId;
|
|
50
55
|
|
|
51
56
|
private readonly config: XaiResponsesConfig;
|
|
52
57
|
|
|
58
|
+
static [WORKFLOW_SERIALIZE](model: XaiResponsesLanguageModel) {
|
|
59
|
+
return serializeModelOptions({
|
|
60
|
+
modelId: model.modelId,
|
|
61
|
+
config: model.config,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static [WORKFLOW_DESERIALIZE](options: {
|
|
66
|
+
modelId: XaiResponsesModelId;
|
|
67
|
+
config: XaiResponsesConfig;
|
|
68
|
+
}) {
|
|
69
|
+
return new XaiResponsesLanguageModel(options.modelId, options.config);
|
|
70
|
+
}
|
|
71
|
+
|
|
53
72
|
constructor(modelId: XaiResponsesModelId, config: XaiResponsesConfig) {
|
|
54
73
|
this.modelId = modelId;
|
|
55
74
|
this.config = config;
|
|
@@ -61,6 +80,11 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
61
80
|
|
|
62
81
|
readonly supportedUrls: Record<string, RegExp[]> = {
|
|
63
82
|
'image/*': [/^https?:\/\/.*$/],
|
|
83
|
+
// xAI's Responses API accepts non-image documents (PDF, plain text, CSV, etc.) as
|
|
84
|
+
// `{ type: 'input_file', file_url }`. Keeping these URLs intact here lets them pass
|
|
85
|
+
// through to the converter instead of being downloaded to bytes by the SDK.
|
|
86
|
+
'application/pdf': [/^https?:\/\/.*$/],
|
|
87
|
+
'text/*': [/^https?:\/\/.*$/],
|
|
64
88
|
};
|
|
65
89
|
|
|
66
90
|
private async getArgs({
|
|
@@ -74,8 +98,9 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
74
98
|
providerOptions,
|
|
75
99
|
tools,
|
|
76
100
|
toolChoice,
|
|
77
|
-
|
|
78
|
-
|
|
101
|
+
reasoning,
|
|
102
|
+
}: LanguageModelV4CallOptions) {
|
|
103
|
+
const warnings: SharedV4Warning[] = [];
|
|
79
104
|
|
|
80
105
|
const options =
|
|
81
106
|
(await parseProviderOptions({
|
|
@@ -110,7 +135,7 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
110
135
|
|
|
111
136
|
const { input, inputWarnings } = await convertToXaiResponsesInput({
|
|
112
137
|
prompt,
|
|
113
|
-
store: true,
|
|
138
|
+
store: options.store ?? true,
|
|
114
139
|
});
|
|
115
140
|
warnings.push(...inputWarnings);
|
|
116
141
|
|
|
@@ -139,6 +164,24 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
139
164
|
}
|
|
140
165
|
}
|
|
141
166
|
|
|
167
|
+
const resolvedReasoningEffort =
|
|
168
|
+
options.reasoningEffort ??
|
|
169
|
+
(isCustomReasoning(reasoning)
|
|
170
|
+
? reasoning === 'none'
|
|
171
|
+
? undefined
|
|
172
|
+
: mapReasoningToProviderEffort({
|
|
173
|
+
reasoning,
|
|
174
|
+
effortMap: {
|
|
175
|
+
minimal: 'low',
|
|
176
|
+
low: 'low',
|
|
177
|
+
medium: 'medium',
|
|
178
|
+
high: 'high',
|
|
179
|
+
xhigh: 'high',
|
|
180
|
+
},
|
|
181
|
+
warnings,
|
|
182
|
+
})
|
|
183
|
+
: undefined);
|
|
184
|
+
|
|
142
185
|
const baseArgs: Record<string, unknown> = {
|
|
143
186
|
model: this.modelId,
|
|
144
187
|
input,
|
|
@@ -165,11 +208,11 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
165
208
|
: { type: 'json_object' },
|
|
166
209
|
},
|
|
167
210
|
}),
|
|
168
|
-
...((
|
|
211
|
+
...((resolvedReasoningEffort != null ||
|
|
169
212
|
options.reasoningSummary != null) && {
|
|
170
213
|
reasoning: {
|
|
171
|
-
...(
|
|
172
|
-
effort:
|
|
214
|
+
...(resolvedReasoningEffort != null && {
|
|
215
|
+
effort: resolvedReasoningEffort,
|
|
173
216
|
}),
|
|
174
217
|
...(options.reasoningSummary != null && {
|
|
175
218
|
summary: options.reasoningSummary,
|
|
@@ -207,8 +250,8 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
207
250
|
}
|
|
208
251
|
|
|
209
252
|
async doGenerate(
|
|
210
|
-
options:
|
|
211
|
-
): Promise<
|
|
253
|
+
options: LanguageModelV4CallOptions,
|
|
254
|
+
): Promise<LanguageModelV4GenerateResult> {
|
|
212
255
|
const {
|
|
213
256
|
args: body,
|
|
214
257
|
warnings,
|
|
@@ -225,7 +268,7 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
225
268
|
rawValue: rawResponse,
|
|
226
269
|
} = await postJsonToApi({
|
|
227
270
|
url: `${this.config.baseURL ?? 'https://api.x.ai/v1'}/responses`,
|
|
228
|
-
headers: combineHeaders(this.config.headers(), options.headers),
|
|
271
|
+
headers: combineHeaders(this.config.headers?.(), options.headers),
|
|
229
272
|
body,
|
|
230
273
|
failedResponseHandler: xaiFailedResponseHandler,
|
|
231
274
|
successfulResponseHandler: createJsonResponseHandler(
|
|
@@ -235,7 +278,8 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
235
278
|
fetch: this.config.fetch,
|
|
236
279
|
});
|
|
237
280
|
|
|
238
|
-
const content: Array<
|
|
281
|
+
const content: Array<LanguageModelV4Content> = [];
|
|
282
|
+
let hasFunctionCall = false;
|
|
239
283
|
|
|
240
284
|
const webSearchSubTools = [
|
|
241
285
|
'web_search',
|
|
@@ -358,6 +402,7 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
358
402
|
}
|
|
359
403
|
|
|
360
404
|
case 'function_call': {
|
|
405
|
+
hasFunctionCall = true;
|
|
361
406
|
content.push({
|
|
362
407
|
type: 'tool-call',
|
|
363
408
|
toolCallId: part.call_id,
|
|
@@ -377,11 +422,13 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
377
422
|
.filter(text => text && text.length > 0)
|
|
378
423
|
.join('');
|
|
379
424
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
425
|
+
// condition changed here since encrypted content can now come with empty reasoning text
|
|
426
|
+
if (reasoningText || part.encrypted_content) {
|
|
427
|
+
const hasMetadata = part.encrypted_content || part.id;
|
|
428
|
+
content.push({
|
|
429
|
+
type: 'reasoning',
|
|
430
|
+
text: reasoningText,
|
|
431
|
+
...(hasMetadata && {
|
|
385
432
|
providerMetadata: {
|
|
386
433
|
xai: {
|
|
387
434
|
...(part.encrypted_content && {
|
|
@@ -390,13 +437,8 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
390
437
|
...(part.id && { itemId: part.id }),
|
|
391
438
|
},
|
|
392
439
|
},
|
|
393
|
-
})
|
|
394
|
-
}
|
|
395
|
-
content.push({
|
|
396
|
-
type: 'reasoning',
|
|
397
|
-
text: reasoningText,
|
|
398
|
-
});
|
|
399
|
-
}
|
|
440
|
+
}),
|
|
441
|
+
});
|
|
400
442
|
}
|
|
401
443
|
break;
|
|
402
444
|
}
|
|
@@ -410,7 +452,9 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
410
452
|
return {
|
|
411
453
|
content,
|
|
412
454
|
finishReason: {
|
|
413
|
-
unified:
|
|
455
|
+
unified: hasFunctionCall
|
|
456
|
+
? 'tool-calls'
|
|
457
|
+
: mapXaiResponsesFinishReason(response.status),
|
|
414
458
|
raw: response.status ?? undefined,
|
|
415
459
|
},
|
|
416
460
|
usage: response.usage
|
|
@@ -419,6 +463,13 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
419
463
|
inputTokens: { total: 0, noCache: 0, cacheRead: 0, cacheWrite: 0 },
|
|
420
464
|
outputTokens: { total: 0, text: 0, reasoning: 0 },
|
|
421
465
|
},
|
|
466
|
+
...(response.usage?.cost_in_usd_ticks != null && {
|
|
467
|
+
providerMetadata: {
|
|
468
|
+
xai: {
|
|
469
|
+
costInUsdTicks: response.usage.cost_in_usd_ticks,
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
}),
|
|
422
473
|
request: { body },
|
|
423
474
|
response: {
|
|
424
475
|
...getResponseMetadata(response),
|
|
@@ -430,8 +481,8 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
430
481
|
}
|
|
431
482
|
|
|
432
483
|
async doStream(
|
|
433
|
-
options:
|
|
434
|
-
): Promise<
|
|
484
|
+
options: LanguageModelV4CallOptions,
|
|
485
|
+
): Promise<LanguageModelV4StreamResult> {
|
|
435
486
|
const {
|
|
436
487
|
args,
|
|
437
488
|
warnings,
|
|
@@ -448,7 +499,7 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
448
499
|
|
|
449
500
|
const { responseHeaders, value: response } = await postJsonToApi({
|
|
450
501
|
url: `${this.config.baseURL ?? 'https://api.x.ai/v1'}/responses`,
|
|
451
|
-
headers: combineHeaders(this.config.headers(), options.headers),
|
|
502
|
+
headers: combineHeaders(this.config.headers?.(), options.headers),
|
|
452
503
|
body,
|
|
453
504
|
failedResponseHandler: xaiFailedResponseHandler,
|
|
454
505
|
successfulResponseHandler: createEventSourceResponseHandler(
|
|
@@ -458,11 +509,13 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
458
509
|
fetch: this.config.fetch,
|
|
459
510
|
});
|
|
460
511
|
|
|
461
|
-
let finishReason:
|
|
512
|
+
let finishReason: LanguageModelV4FinishReason = {
|
|
462
513
|
unified: 'other',
|
|
463
514
|
raw: undefined,
|
|
464
515
|
};
|
|
465
|
-
let
|
|
516
|
+
let hasFunctionCall = false;
|
|
517
|
+
let usage: LanguageModelV4Usage | undefined = undefined;
|
|
518
|
+
let costInUsdTicks: number | undefined = undefined;
|
|
466
519
|
let isFirstChunk = true;
|
|
467
520
|
const contentBlocks: Record<string, { type: 'text' }> = {};
|
|
468
521
|
const seenToolCalls = new Set<string>();
|
|
@@ -485,7 +538,7 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
485
538
|
stream: response.pipeThrough(
|
|
486
539
|
new TransformStream<
|
|
487
540
|
ParseResult<z.infer<typeof xaiResponsesChunkSchema>>,
|
|
488
|
-
|
|
541
|
+
LanguageModelV4StreamPart
|
|
489
542
|
>({
|
|
490
543
|
start(controller) {
|
|
491
544
|
controller.enqueue({ type: 'stream-start', warnings });
|
|
@@ -520,16 +573,18 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
520
573
|
if (event.type === 'response.reasoning_summary_part.added') {
|
|
521
574
|
const blockId = `reasoning-${event.item_id}`;
|
|
522
575
|
|
|
523
|
-
activeReasoning[event.item_id]
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
576
|
+
if (activeReasoning[event.item_id] == null) {
|
|
577
|
+
activeReasoning[event.item_id] = {};
|
|
578
|
+
controller.enqueue({
|
|
579
|
+
type: 'reasoning-start',
|
|
580
|
+
id: blockId,
|
|
581
|
+
providerMetadata: {
|
|
582
|
+
xai: {
|
|
583
|
+
itemId: event.item_id,
|
|
584
|
+
},
|
|
530
585
|
},
|
|
531
|
-
}
|
|
532
|
-
}
|
|
586
|
+
});
|
|
587
|
+
}
|
|
533
588
|
}
|
|
534
589
|
|
|
535
590
|
if (event.type === 'response.reasoning_summary_text.delta') {
|
|
@@ -645,17 +700,32 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
645
700
|
|
|
646
701
|
if (
|
|
647
702
|
event.type === 'response.done' ||
|
|
648
|
-
event.type === 'response.completed'
|
|
703
|
+
event.type === 'response.completed' ||
|
|
704
|
+
event.type === 'response.incomplete'
|
|
649
705
|
) {
|
|
650
706
|
const response = event.response;
|
|
651
707
|
|
|
652
708
|
if (response.usage) {
|
|
653
709
|
usage = convertXaiResponsesUsage(response.usage);
|
|
710
|
+
costInUsdTicks = response.usage.cost_in_usd_ticks ?? undefined;
|
|
654
711
|
}
|
|
655
712
|
|
|
656
|
-
if (response.
|
|
713
|
+
if (event.type === 'response.incomplete') {
|
|
714
|
+
const reason =
|
|
715
|
+
'incomplete_details' in response
|
|
716
|
+
? response.incomplete_details?.reason
|
|
717
|
+
: undefined;
|
|
657
718
|
finishReason = {
|
|
658
|
-
unified:
|
|
719
|
+
unified: reason
|
|
720
|
+
? mapXaiResponsesFinishReason(reason)
|
|
721
|
+
: 'other',
|
|
722
|
+
raw: reason ?? 'incomplete',
|
|
723
|
+
};
|
|
724
|
+
} else if ('status' in response && response.status) {
|
|
725
|
+
finishReason = {
|
|
726
|
+
unified: hasFunctionCall
|
|
727
|
+
? 'tool-calls'
|
|
728
|
+
: mapXaiResponsesFinishReason(response.status),
|
|
659
729
|
raw: response.status,
|
|
660
730
|
};
|
|
661
731
|
}
|
|
@@ -663,6 +733,25 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
663
733
|
return;
|
|
664
734
|
}
|
|
665
735
|
|
|
736
|
+
if (event.type === 'response.failed') {
|
|
737
|
+
const reason = event.response.incomplete_details?.reason;
|
|
738
|
+
finishReason = {
|
|
739
|
+
unified: reason ? mapXaiResponsesFinishReason(reason) : 'error',
|
|
740
|
+
raw: reason ?? 'error',
|
|
741
|
+
};
|
|
742
|
+
|
|
743
|
+
if (event.response.usage) {
|
|
744
|
+
usage = convertXaiResponsesUsage(event.response.usage);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
if (event.type === 'error') {
|
|
751
|
+
controller.enqueue({ type: 'error', error: event });
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
|
|
666
755
|
// Custom tool call input streaming - already handled by output_item events
|
|
667
756
|
if (
|
|
668
757
|
event.type === 'response.custom_tool_call_input.delta' ||
|
|
@@ -923,6 +1012,7 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
923
1012
|
toolName: part.name,
|
|
924
1013
|
});
|
|
925
1014
|
} else if (event.type === 'response.output_item.done') {
|
|
1015
|
+
hasFunctionCall = true;
|
|
926
1016
|
ongoingToolCalls[event.output_index] = undefined;
|
|
927
1017
|
|
|
928
1018
|
controller.enqueue({
|
|
@@ -963,6 +1053,13 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
|
|
|
963
1053
|
},
|
|
964
1054
|
outputTokens: { total: 0, text: 0, reasoning: 0 },
|
|
965
1055
|
},
|
|
1056
|
+
...(costInUsdTicks != null && {
|
|
1057
|
+
providerMetadata: {
|
|
1058
|
+
xai: {
|
|
1059
|
+
costInUsdTicks,
|
|
1060
|
+
},
|
|
1061
|
+
},
|
|
1062
|
+
}),
|
|
966
1063
|
});
|
|
967
1064
|
},
|
|
968
1065
|
}),
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
-
LanguageModelV3CallOptions,
|
|
3
|
-
SharedV3Warning,
|
|
4
2
|
UnsupportedFunctionalityError,
|
|
3
|
+
type LanguageModelV4CallOptions,
|
|
4
|
+
type SharedV4Warning,
|
|
5
5
|
} from '@ai-sdk/provider';
|
|
6
6
|
import { validateTypes } from '@ai-sdk/provider-utils';
|
|
7
|
+
import { removeAdditionalPropertiesFalse } from '../remove-additional-properties';
|
|
7
8
|
import { fileSearchArgsSchema } from '../tool/file-search';
|
|
8
9
|
import { mcpServerArgsSchema } from '../tool/mcp-server';
|
|
9
10
|
import { webSearchArgsSchema } from '../tool/web-search';
|
|
10
11
|
import { xSearchArgsSchema } from '../tool/x-search';
|
|
11
|
-
import { XaiResponsesTool } from './xai-responses-api';
|
|
12
|
+
import type { XaiResponsesTool } from './xai-responses-api';
|
|
12
13
|
|
|
13
14
|
type XaiResponsesToolChoice =
|
|
14
15
|
| 'auto'
|
|
@@ -20,16 +21,16 @@ export async function prepareResponsesTools({
|
|
|
20
21
|
tools,
|
|
21
22
|
toolChoice,
|
|
22
23
|
}: {
|
|
23
|
-
tools:
|
|
24
|
-
toolChoice?:
|
|
24
|
+
tools: LanguageModelV4CallOptions['tools'];
|
|
25
|
+
toolChoice?: LanguageModelV4CallOptions['toolChoice'];
|
|
25
26
|
}): Promise<{
|
|
26
27
|
tools: Array<XaiResponsesTool> | undefined;
|
|
27
28
|
toolChoice: XaiResponsesToolChoice | undefined;
|
|
28
|
-
toolWarnings:
|
|
29
|
+
toolWarnings: SharedV4Warning[];
|
|
29
30
|
}> {
|
|
30
31
|
const normalizedTools = tools?.length ? tools : undefined;
|
|
31
32
|
|
|
32
|
-
const toolWarnings:
|
|
33
|
+
const toolWarnings: SharedV4Warning[] = [];
|
|
33
34
|
|
|
34
35
|
if (normalizedTools == null) {
|
|
35
36
|
return { tools: undefined, toolChoice: undefined, toolWarnings };
|
|
@@ -53,6 +54,7 @@ export async function prepareResponsesTools({
|
|
|
53
54
|
type: 'web_search',
|
|
54
55
|
allowed_domains: args.allowedDomains,
|
|
55
56
|
excluded_domains: args.excludedDomains,
|
|
57
|
+
enable_image_search: args.enableImageSearch,
|
|
56
58
|
enable_image_understanding: args.enableImageUnderstanding,
|
|
57
59
|
});
|
|
58
60
|
break;
|
|
@@ -142,7 +144,7 @@ export async function prepareResponsesTools({
|
|
|
142
144
|
type: 'function',
|
|
143
145
|
name: tool.name,
|
|
144
146
|
description: tool.description,
|
|
145
|
-
parameters: tool.inputSchema,
|
|
147
|
+
parameters: removeAdditionalPropertiesFalse(tool.inputSchema),
|
|
146
148
|
...(tool.strict != null ? { strict: tool.strict } : {}),
|
|
147
149
|
});
|
|
148
150
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createProviderExecutedToolFactory } from '@ai-sdk/provider-utils';
|
|
2
2
|
import { z } from 'zod/v4';
|
|
3
3
|
|
|
4
4
|
const codeExecutionOutputSchema = z.object({
|
|
@@ -6,7 +6,7 @@ const codeExecutionOutputSchema = z.object({
|
|
|
6
6
|
error: z.string().optional().describe('any error that occurred'),
|
|
7
7
|
});
|
|
8
8
|
|
|
9
|
-
const codeExecutionToolFactory =
|
|
9
|
+
const codeExecutionToolFactory = createProviderExecutedToolFactory({
|
|
10
10
|
id: 'xai.code_execution',
|
|
11
11
|
inputSchema: z.object({}).describe('no input parameters'),
|
|
12
12
|
outputSchema: codeExecutionOutputSchema,
|
package/src/tool/file-search.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
createProviderExecutedToolFactory,
|
|
3
3
|
lazySchema,
|
|
4
4
|
zodSchema,
|
|
5
5
|
} from '@ai-sdk/provider-utils';
|
|
@@ -36,7 +36,7 @@ const fileSearchOutputSchema = lazySchema(() =>
|
|
|
36
36
|
),
|
|
37
37
|
);
|
|
38
38
|
|
|
39
|
-
const fileSearchToolFactory =
|
|
39
|
+
const fileSearchToolFactory = createProviderExecutedToolFactory<
|
|
40
40
|
{},
|
|
41
41
|
{
|
|
42
42
|
/**
|
package/src/tool/mcp-server.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
createProviderExecutedToolFactory,
|
|
3
3
|
lazySchema,
|
|
4
4
|
zodSchema,
|
|
5
5
|
} from '@ai-sdk/provider-utils';
|
|
@@ -41,7 +41,7 @@ const mcpServerOutputSchema = lazySchema(() =>
|
|
|
41
41
|
),
|
|
42
42
|
);
|
|
43
43
|
|
|
44
|
-
const mcpServerToolFactory =
|
|
44
|
+
const mcpServerToolFactory = createProviderExecutedToolFactory<
|
|
45
45
|
{},
|
|
46
46
|
{
|
|
47
47
|
name: string;
|
package/src/tool/view-image.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createProviderExecutedToolFactory } from '@ai-sdk/provider-utils';
|
|
2
2
|
import { z } from 'zod/v4';
|
|
3
3
|
|
|
4
4
|
const viewImageOutputSchema = z.object({
|
|
@@ -9,7 +9,7 @@ const viewImageOutputSchema = z.object({
|
|
|
9
9
|
.describe('objects detected in the image'),
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
-
const viewImageToolFactory =
|
|
12
|
+
const viewImageToolFactory = createProviderExecutedToolFactory({
|
|
13
13
|
id: 'xai.view_image',
|
|
14
14
|
inputSchema: z.object({}).describe('no input parameters'),
|
|
15
15
|
outputSchema: viewImageOutputSchema,
|
package/src/tool/view-x-video.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createProviderExecutedToolFactory } from '@ai-sdk/provider-utils';
|
|
2
2
|
import { z } from 'zod/v4';
|
|
3
3
|
|
|
4
4
|
const viewXVideoOutputSchema = z.object({
|
|
@@ -7,7 +7,7 @@ const viewXVideoOutputSchema = z.object({
|
|
|
7
7
|
duration: z.number().optional().describe('duration in seconds'),
|
|
8
8
|
});
|
|
9
9
|
|
|
10
|
-
const viewXVideoToolFactory =
|
|
10
|
+
const viewXVideoToolFactory = createProviderExecutedToolFactory({
|
|
11
11
|
id: 'xai.view_x_video',
|
|
12
12
|
inputSchema: z.object({}).describe('no input parameters'),
|
|
13
13
|
outputSchema: viewXVideoOutputSchema,
|