@better-agent/providers 0.1.0-canary.0

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,1277 @@
1
+ import { n as extractPassthroughOptions, r as omitNullish, t as baFetch } from "../fetch-CW0dWlVC.mjs";
2
+ import { Events } from "@better-agent/core/events";
3
+ import { BetterAgentError } from "@better-agent/shared/errors";
4
+ import { err, ok } from "@better-agent/shared/neverthrow";
5
+ import { z } from "zod";
6
+ import { safeJsonParse } from "@better-agent/shared/utils";
7
+ import { TOOL_JSON_SCHEMA, isCallableToolDefinition } from "@better-agent/core";
8
+
9
+ //#region src/xai/client/auth.ts
10
+ const buildXAIHeaders = (config) => {
11
+ const headers = { ...config.headers ?? {} };
12
+ if (config.apiKey) headers.Authorization = `Bearer ${config.apiKey}`;
13
+ return headers;
14
+ };
15
+
16
+ //#endregion
17
+ //#region src/xai/client/errors.ts
18
+ const mapXAIHttpError = (httpError, ctx) => {
19
+ if (!httpError) return BetterAgentError.fromCode("UPSTREAM_FAILED", "xAI request failed", { context: { provider: "xai" } }).at({
20
+ at: ctx.at,
21
+ data: { path: ctx.path }
22
+ });
23
+ const { status, statusText, error } = httpError;
24
+ const message = error?.message ?? statusText ?? "xAI request failed";
25
+ const code = String(error?.code ?? error?.type ?? status);
26
+ return BetterAgentError.fromCode("UPSTREAM_FAILED", message, {
27
+ status,
28
+ context: {
29
+ provider: "xai",
30
+ upstreamCode: code,
31
+ raw: error
32
+ }
33
+ }).at({
34
+ at: ctx.at,
35
+ data: {
36
+ path: ctx.path,
37
+ status
38
+ }
39
+ });
40
+ };
41
+
42
+ //#endregion
43
+ //#region src/xai/client/stream.ts
44
+ const unwrapXAIStreamJson = (parsed) => {
45
+ if (!parsed || typeof parsed !== "object") return parsed;
46
+ const obj = parsed;
47
+ if ("data" in obj) return obj.data;
48
+ if ("value" in obj) return obj.value;
49
+ return obj;
50
+ };
51
+
52
+ //#endregion
53
+ //#region src/xai/client/create-client.ts
54
+ const createXAIClient = (config = {}) => {
55
+ const baseUrl = (config.baseURL ?? "https://api.x.ai").replace(/\/+$/, "");
56
+ const headers = buildXAIHeaders(config);
57
+ const post = async (path, body, at, options) => {
58
+ try {
59
+ const result = await baFetch(`${baseUrl}${path}`, {
60
+ method: "POST",
61
+ body: JSON.stringify(body),
62
+ headers: {
63
+ ...headers,
64
+ "Content-Type": "application/json"
65
+ },
66
+ signal: options?.signal ?? null,
67
+ throw: false
68
+ });
69
+ if (result.error) return err(mapXAIHttpError(result.error, {
70
+ at,
71
+ path
72
+ }).at({
73
+ at,
74
+ data: { path }
75
+ }));
76
+ if (!result.data) return err(BetterAgentError.fromCode("UPSTREAM_FAILED", "xAI returned no data", { context: { provider: "xai" } }).at({
77
+ at,
78
+ data: { path }
79
+ }));
80
+ return ok(result.data);
81
+ } catch (e) {
82
+ return err(BetterAgentError.wrap({
83
+ err: e,
84
+ message: "xAI request failed",
85
+ opts: {
86
+ code: "UPSTREAM_FAILED",
87
+ context: { provider: "xai" }
88
+ }
89
+ }).at({
90
+ at,
91
+ data: { path }
92
+ }));
93
+ }
94
+ };
95
+ const get = async (path, at, options) => {
96
+ try {
97
+ const result = await baFetch(`${baseUrl}${path}`, {
98
+ method: "GET",
99
+ headers,
100
+ signal: options?.signal ?? null,
101
+ throw: false
102
+ });
103
+ if (result.error) return err(mapXAIHttpError(result.error, {
104
+ at,
105
+ path
106
+ }).at({
107
+ at,
108
+ data: { path }
109
+ }));
110
+ if (!result.data) return err(BetterAgentError.fromCode("UPSTREAM_FAILED", "xAI returned no data", { context: { provider: "xai" } }).at({
111
+ at,
112
+ data: { path }
113
+ }));
114
+ return ok(result.data);
115
+ } catch (e) {
116
+ return err(BetterAgentError.wrap({
117
+ err: e,
118
+ message: "xAI request failed",
119
+ opts: {
120
+ code: "UPSTREAM_FAILED",
121
+ context: { provider: "xai" }
122
+ }
123
+ }).at({
124
+ at,
125
+ data: { path }
126
+ }));
127
+ }
128
+ };
129
+ const del = async (path, at, options) => {
130
+ try {
131
+ const result = await baFetch(`${baseUrl}${path}`, {
132
+ method: "DELETE",
133
+ headers,
134
+ signal: options?.signal ?? null,
135
+ throw: false
136
+ });
137
+ if (result.error) return err(mapXAIHttpError(result.error, {
138
+ at,
139
+ path
140
+ }).at({
141
+ at,
142
+ data: { path }
143
+ }));
144
+ if (!result.data) return err(BetterAgentError.fromCode("UPSTREAM_FAILED", "xAI returned no data", { context: { provider: "xai" } }).at({
145
+ at,
146
+ data: { path }
147
+ }));
148
+ return ok(result.data);
149
+ } catch (e) {
150
+ return err(BetterAgentError.wrap({
151
+ err: e,
152
+ message: "xAI request failed",
153
+ opts: {
154
+ code: "UPSTREAM_FAILED",
155
+ context: { provider: "xai" }
156
+ }
157
+ }).at({
158
+ at,
159
+ data: { path }
160
+ }));
161
+ }
162
+ };
163
+ const uploadFile = async (path, body, at, options) => {
164
+ const formData = new FormData();
165
+ try {
166
+ const filename = body.filename ?? (typeof File !== "undefined" && body.file instanceof File ? body.file.name : "file");
167
+ const blob = body.file instanceof Blob ? body.file : new Blob([new Uint8Array(body.file)], { type: body.mimeType ?? "application/octet-stream" });
168
+ formData.append("purpose", body.purpose ?? "assistants");
169
+ formData.append("file", blob, filename);
170
+ const response = await fetch(`${baseUrl}${path}`, {
171
+ method: "POST",
172
+ body: formData,
173
+ headers,
174
+ signal: options?.signal ?? null
175
+ });
176
+ if (!response.ok) {
177
+ let xaiError;
178
+ try {
179
+ xaiError = await response.json();
180
+ } catch {}
181
+ return err(mapXAIHttpError({
182
+ status: response.status,
183
+ statusText: response.statusText,
184
+ error: xaiError?.error
185
+ }, {
186
+ at,
187
+ path
188
+ }));
189
+ }
190
+ const data = await response.json();
191
+ if (!data) return err(BetterAgentError.fromCode("UPSTREAM_FAILED", "xAI returned no data", { context: { provider: "xai" } }).at({
192
+ at,
193
+ data: { path }
194
+ }));
195
+ return ok(data);
196
+ } catch (e) {
197
+ return err(BetterAgentError.wrap({
198
+ err: e,
199
+ message: "xAI file upload failed",
200
+ opts: {
201
+ code: "UPSTREAM_FAILED",
202
+ context: { provider: "xai" }
203
+ }
204
+ }).at({
205
+ at,
206
+ data: { path }
207
+ }));
208
+ }
209
+ };
210
+ const getBinary = async (path, at, options) => {
211
+ let response;
212
+ try {
213
+ response = await fetch(`${baseUrl}${path}`, {
214
+ method: "GET",
215
+ headers,
216
+ signal: options?.signal ?? null
217
+ });
218
+ } catch (e) {
219
+ return err(BetterAgentError.wrap({
220
+ err: e,
221
+ message: "xAI request failed",
222
+ opts: {
223
+ code: "UPSTREAM_FAILED",
224
+ context: { provider: "xai" }
225
+ }
226
+ }).at({
227
+ at,
228
+ data: { path }
229
+ }));
230
+ }
231
+ if (!response.ok) {
232
+ let xaiError;
233
+ try {
234
+ xaiError = await response.json();
235
+ } catch {}
236
+ return err(mapXAIHttpError({
237
+ status: response.status,
238
+ statusText: response.statusText,
239
+ error: xaiError?.error
240
+ }, {
241
+ at,
242
+ path
243
+ }));
244
+ }
245
+ return ok(new Uint8Array(await response.arrayBuffer()));
246
+ };
247
+ const streamSSE = async (path, body, at, options) => {
248
+ let response;
249
+ try {
250
+ response = await fetch(`${baseUrl}${path}`, {
251
+ method: "POST",
252
+ headers: {
253
+ ...headers,
254
+ Accept: "text/event-stream",
255
+ "Content-Type": "application/json"
256
+ },
257
+ body: JSON.stringify(body),
258
+ signal: options?.signal ?? null
259
+ });
260
+ } catch (e) {
261
+ return err(BetterAgentError.wrap({
262
+ err: e,
263
+ message: "xAI stream request failed",
264
+ opts: {
265
+ code: "UPSTREAM_FAILED",
266
+ context: { provider: "xai" }
267
+ }
268
+ }).at({
269
+ at,
270
+ data: { path }
271
+ }));
272
+ }
273
+ if (!response.ok || !response.body) {
274
+ let xaiError;
275
+ try {
276
+ xaiError = await response.json();
277
+ } catch {}
278
+ return err(mapXAIHttpError({
279
+ status: response.status,
280
+ statusText: response.statusText,
281
+ error: xaiError?.error
282
+ }, {
283
+ at,
284
+ path
285
+ }));
286
+ }
287
+ const reader = response.body.getReader();
288
+ const decoder = new TextDecoder();
289
+ return ok((async function* () {
290
+ let buffer = "";
291
+ try {
292
+ while (true) {
293
+ const { done, value } = await reader.read();
294
+ if (done) break;
295
+ buffer += decoder.decode(value, { stream: true });
296
+ const chunks = buffer.split("\n\n");
297
+ buffer = chunks.pop() ?? "";
298
+ for (const chunk of chunks) {
299
+ const dataLines = chunk.split("\n").map((line) => line.trim()).filter(Boolean).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim());
300
+ for (const data of dataLines) {
301
+ if (!data || data === "[DONE]") continue;
302
+ const parsed = safeJsonParse(String(unwrapXAIStreamJson(data)));
303
+ if (parsed.isErr() || !parsed.value || typeof parsed.value !== "object") {
304
+ yield err(BetterAgentError.fromCode("UPSTREAM_FAILED", "xAI returned an invalid stream event", { context: {
305
+ provider: "xai",
306
+ raw: data
307
+ } }).at({
308
+ at,
309
+ data: { path }
310
+ }));
311
+ return;
312
+ }
313
+ yield ok(parsed.value);
314
+ }
315
+ }
316
+ }
317
+ } catch (e) {
318
+ yield err(BetterAgentError.wrap({
319
+ err: e,
320
+ message: "xAI stream read failed",
321
+ opts: {
322
+ code: "UPSTREAM_FAILED",
323
+ context: { provider: "xai" }
324
+ }
325
+ }).at({
326
+ at,
327
+ data: { path }
328
+ }));
329
+ } finally {
330
+ reader.releaseLock();
331
+ }
332
+ })());
333
+ };
334
+ return {
335
+ responses: {
336
+ create: (body, options) => post("/v1/responses", body, "xai.http.responses.create", options),
337
+ stream: (body, options) => streamSSE("/v1/responses", {
338
+ ...body,
339
+ stream: true
340
+ }, "xai.http.responses.stream", options)
341
+ },
342
+ images: {
343
+ create: (body, options) => post("/v1/images/generations", body, "xai.http.images.create", options),
344
+ edit: (body, options) => post("/v1/images/edits", body, "xai.http.images.edit", options)
345
+ },
346
+ files: {
347
+ upload: (body, options) => uploadFile("/v1/files", body, "xai.http.files.upload", options),
348
+ list: (options) => get("/v1/files", "xai.http.files.list", options),
349
+ retrieve: (fileId, options) => get(`/v1/files/${encodeURIComponent(fileId)}`, "xai.http.files.retrieve", options),
350
+ delete: (fileId, options) => del(`/v1/files/${encodeURIComponent(fileId)}`, "xai.http.files.delete", options),
351
+ content: (fileId, options) => getBinary(`/v1/files/${encodeURIComponent(fileId)}/content`, "xai.http.files.content", options)
352
+ }
353
+ };
354
+ };
355
+
356
+ //#endregion
357
+ //#region src/xai/images/mappers.ts
358
+ /**
359
+ * Keys explicitly handled by the xAI images mapper.
360
+ * Everything else on the options object is passed through to the API body.
361
+ */
362
+ const XAI_IMAGE_KNOWN_KEYS = new Set([
363
+ "input",
364
+ "tools",
365
+ "toolChoice",
366
+ "modalities",
367
+ "structured_output",
368
+ "n",
369
+ "quality",
370
+ "response_format",
371
+ "size",
372
+ "style",
373
+ "aspect_ratio",
374
+ "resolution",
375
+ "user"
376
+ ]);
377
+ const toImageDataUrl = (source) => source.kind === "url" ? source.url : `data:${source.mimeType};base64,${source.data}`;
378
+ const parseXAIImagePromptInput = (args) => {
379
+ const input = args.options.input;
380
+ if (Array.isArray(input) && input.length > 1) throw BetterAgentError.fromCode("VALIDATION_FAILED", "Image generation supports a single input item", { context: {
381
+ provider: "xai",
382
+ model: args.modelId
383
+ } }).at({ at: "xai.images.map.inputLimit" });
384
+ const first = Array.isArray(input) ? input[0] : input;
385
+ if (typeof first === "string") return {
386
+ prompt: first,
387
+ images: []
388
+ };
389
+ if (!first || typeof first !== "object" || !("type" in first) || first.type !== "message") throw BetterAgentError.fromCode("VALIDATION_FAILED", "xAI image generation requires a prompt string or a single message input.", { context: {
390
+ provider: "xai",
391
+ model: args.modelId
392
+ } }).at({ at: "xai.images.map.inputShape" });
393
+ if (typeof first.content === "string") return {
394
+ prompt: first.content,
395
+ images: []
396
+ };
397
+ const promptParts = [];
398
+ const images = [];
399
+ for (const part of first.content) {
400
+ if (part.type === "text") {
401
+ promptParts.push(part.text);
402
+ continue;
403
+ }
404
+ if (part.type === "image") {
405
+ images.push(part.source);
406
+ continue;
407
+ }
408
+ throw BetterAgentError.fromCode("VALIDATION_FAILED", "xAI image generation only supports text and image input parts.", { context: {
409
+ provider: "xai",
410
+ model: args.modelId
411
+ } }).at({ at: "xai.images.map.partType" });
412
+ }
413
+ return {
414
+ prompt: promptParts.join("\n"),
415
+ images
416
+ };
417
+ };
418
+ function mapToXAIImagesRequest(args) {
419
+ try {
420
+ const o = args.options;
421
+ if ("stream" in o && o.stream) return err(BetterAgentError.fromCode("VALIDATION_FAILED", "Image streaming is not supported by the xAI provider.", { context: {
422
+ provider: "xai",
423
+ model: args.modelId
424
+ } }).at({ at: "xai.images.map.streamUnsupported" }));
425
+ const parsed = parseXAIImagePromptInput(args);
426
+ const prompt = parsed.prompt;
427
+ if (!prompt || prompt.trim().length === 0) return err(BetterAgentError.fromCode("VALIDATION_FAILED", "xAI image generation requires a text prompt.", { context: {
428
+ provider: "xai",
429
+ model: args.modelId
430
+ } }).at({ at: "xai.images.map.prompt" }));
431
+ const imageOptions = o;
432
+ if (parsed.images.length === 0) return ok({
433
+ mode: "generate",
434
+ body: {
435
+ ...extractPassthroughOptions(imageOptions, XAI_IMAGE_KNOWN_KEYS),
436
+ model: args.modelId,
437
+ prompt,
438
+ ...omitNullish({
439
+ n: imageOptions.n,
440
+ quality: imageOptions.quality,
441
+ response_format: imageOptions.response_format,
442
+ size: imageOptions.size,
443
+ style: imageOptions.style,
444
+ user: imageOptions.user
445
+ })
446
+ }
447
+ });
448
+ const firstImage = parsed.images[0];
449
+ if (!firstImage) throw BetterAgentError.fromCode("VALIDATION_FAILED", "xAI image generation requires at least one image when editing", { context: {
450
+ provider: "xai",
451
+ model: args.modelId
452
+ } }).at({ at: "xai.images.map.firstImageMissing" });
453
+ return ok({
454
+ mode: "edit",
455
+ body: {
456
+ ...extractPassthroughOptions(imageOptions, XAI_IMAGE_KNOWN_KEYS),
457
+ model: args.modelId,
458
+ prompt,
459
+ ...parsed.images.length === 1 ? { image: {
460
+ type: "image_url",
461
+ image_url: toImageDataUrl(firstImage)
462
+ } } : { images: parsed.images.map((image) => ({
463
+ type: "image_url",
464
+ image_url: toImageDataUrl(image)
465
+ })) },
466
+ ...omitNullish({
467
+ n: imageOptions.n,
468
+ quality: imageOptions.quality,
469
+ response_format: imageOptions.response_format,
470
+ size: imageOptions.size,
471
+ style: imageOptions.style,
472
+ aspect_ratio: imageOptions.aspect_ratio,
473
+ resolution: imageOptions.resolution,
474
+ user: imageOptions.user
475
+ })
476
+ }
477
+ });
478
+ } catch (e) {
479
+ return err(BetterAgentError.wrap({
480
+ err: e,
481
+ message: "Failed to map xAI image request",
482
+ opts: {
483
+ code: "INTERNAL",
484
+ context: {
485
+ provider: "xai",
486
+ model: args.modelId
487
+ }
488
+ }
489
+ }).at({ at: "xai.images.mapToRequest" }));
490
+ }
491
+ }
492
+ function mapFromXAIImagesResponse(raw) {
493
+ const output = (raw.data ?? []).map(outputMapper).filter(isDefined);
494
+ const usage = typeof raw.usage?.cost_in_usd_ticks === "number" ? { totalTokens: raw.usage.cost_in_usd_ticks } : {};
495
+ const images = (raw.data ?? []).map((item) => ({ ...omitNullish({
496
+ url: typeof item.url === "string" ? item.url : void 0,
497
+ b64_json: typeof item.b64_json === "string" ? item.b64_json : void 0,
498
+ mime_type: typeof item.mime_type === "string" ? item.mime_type : void 0,
499
+ revised_prompt: typeof item.revised_prompt === "string" ? item.revised_prompt : void 0
500
+ }) }));
501
+ return {
502
+ output,
503
+ finishReason: "stop",
504
+ usage,
505
+ response: { body: {
506
+ ...raw,
507
+ normalized: {
508
+ images,
509
+ usage: raw.usage
510
+ }
511
+ } }
512
+ };
513
+ }
514
+ function outputMapper(item) {
515
+ if (!item || typeof item !== "object") return null;
516
+ const image = item;
517
+ const url = typeof image.url === "string" ? image.url : null;
518
+ const b64 = typeof image.b64_json === "string" ? image.b64_json : null;
519
+ const mimeType = typeof image.mime_type === "string" ? image.mime_type : void 0;
520
+ const revisedPrompt = typeof image.revised_prompt === "string" ? image.revised_prompt : void 0;
521
+ if (!url && !b64) return null;
522
+ if (b64) return {
523
+ type: "message",
524
+ role: "assistant",
525
+ content: [{
526
+ type: "image",
527
+ source: {
528
+ kind: "base64",
529
+ data: b64,
530
+ mimeType: mimeType ?? "image/png"
531
+ },
532
+ ...revisedPrompt ? { revisedPrompt } : {}
533
+ }]
534
+ };
535
+ if (url == null) return null;
536
+ return {
537
+ type: "message",
538
+ role: "assistant",
539
+ content: [{
540
+ type: "image",
541
+ source: {
542
+ kind: "url",
543
+ url
544
+ },
545
+ ...mimeType ? { mimeType } : {},
546
+ ...revisedPrompt ? { revisedPrompt } : {}
547
+ }]
548
+ };
549
+ }
550
+ function isDefined(value) {
551
+ return value !== null;
552
+ }
553
+
554
+ //#endregion
555
+ //#region src/xai/images/model.ts
556
+ const XAI_IMAGE_CAPS = {
557
+ inputModalities: {
558
+ text: true,
559
+ image: true
560
+ },
561
+ inputShape: "prompt",
562
+ replayMode: "single_turn_persistent",
563
+ supportsInstruction: false,
564
+ outputModalities: { image: true },
565
+ additionalSupportedRoles: ["developer"]
566
+ };
567
+ const createXAIImagesModel = (modelId, client) => {
568
+ const doGenerate = async (options, ctx) => {
569
+ const requestBodyResult = mapToXAIImagesRequest({
570
+ modelId,
571
+ options
572
+ });
573
+ if (requestBodyResult.isErr()) return err(requestBodyResult.error.at({ at: "xai.images.generate.mapRequest" }));
574
+ const request = requestBodyResult.value;
575
+ const raw = request.mode === "edit" ? await client.images.edit(request.body, { signal: ctx.signal ?? null }) : await client.images.create(request.body, { signal: ctx.signal ?? null });
576
+ if (raw.isErr()) return err(raw.error.at({ at: "xai.images.generate.http" }));
577
+ return ok({ response: {
578
+ ...mapFromXAIImagesResponse(raw.value),
579
+ request: { body: request.body }
580
+ } });
581
+ };
582
+ return {
583
+ providerId: "xai",
584
+ modelId,
585
+ caps: XAI_IMAGE_CAPS,
586
+ doGenerate
587
+ };
588
+ };
589
+
590
+ //#endregion
591
+ //#region src/xai/tools/index.ts
592
+ function createXAINativeToolBuilders() {
593
+ return {
594
+ webSearch: (config = {}) => createNativeTool("web_search", config),
595
+ xSearch: (config = {}) => createNativeTool("x_search", config),
596
+ codeExecution: (config = {}) => createNativeTool("code_execution", config),
597
+ codeInterpreter: (config = {}) => createNativeTool("code_interpreter", config),
598
+ attachmentSearch: (config = {}) => createNativeTool("attachment_search", config),
599
+ collectionsSearch: (config = {}) => createNativeTool("collections_search", config),
600
+ fileSearch: (config = {}) => createNativeTool("file_search", config),
601
+ mcp: (config) => createNativeTool("mcp", config)
602
+ };
603
+ }
604
+ function createNativeTool(type, config) {
605
+ return {
606
+ kind: "hosted",
607
+ provider: "xai",
608
+ type,
609
+ config
610
+ };
611
+ }
612
+ function isXAINativeToolDefinition(tool) {
613
+ if (!tool || typeof tool !== "object") return false;
614
+ const t = tool;
615
+ return t.kind === "hosted" && t.provider === "xai" && typeof t.type === "string";
616
+ }
617
+ function mapXAINativeToolToRequest(tool) {
618
+ return {
619
+ type: tool.type,
620
+ ...tool.config
621
+ };
622
+ }
623
+
624
+ //#endregion
625
+ //#region src/xai/responses/mappers.ts
626
+ /**
627
+ * Keys explicitly handled by the xAI responses mapper.
628
+ */
629
+ const XAI_RESPONSE_KNOWN_KEYS = new Set([
630
+ "input",
631
+ "tools",
632
+ "toolChoice",
633
+ "modalities",
634
+ "structured_output",
635
+ "include",
636
+ "instructions",
637
+ "logprobs",
638
+ "max_output_tokens",
639
+ "metadata",
640
+ "parallel_tool_calls",
641
+ "previous_response_id",
642
+ "reasoning",
643
+ "search_parameters",
644
+ "service_tier",
645
+ "store",
646
+ "temperature",
647
+ "top_logprobs",
648
+ "top_p",
649
+ "user"
650
+ ]);
651
+ function mapToXAIResponsesRequest(args) {
652
+ try {
653
+ const o = args.options;
654
+ const raw = o;
655
+ const input = typeof o.input === "string" ? [{
656
+ role: "user",
657
+ content: [{
658
+ type: "input_text",
659
+ text: o.input
660
+ }]
661
+ }] : o.input.flatMap((item) => {
662
+ if (typeof item === "string") return [{
663
+ role: "user",
664
+ content: [{
665
+ type: "input_text",
666
+ text: item
667
+ }]
668
+ }];
669
+ if (item.type === "message") {
670
+ const role = typeof item.role === "string" && (item.role === "system" || item.role === "user" || item.role === "assistant" || item.role === "developer") ? item.role : "user";
671
+ const isAssistant = role === "assistant";
672
+ return [{
673
+ role,
674
+ content: typeof item.content === "string" ? [isAssistant ? {
675
+ type: "output_text",
676
+ text: item.content
677
+ } : {
678
+ type: "input_text",
679
+ text: item.content
680
+ }] : item.content.map((part) => {
681
+ if (part.type === "text") return isAssistant ? {
682
+ type: "output_text",
683
+ text: part.text
684
+ } : {
685
+ type: "input_text",
686
+ text: part.text
687
+ };
688
+ if (isAssistant) throw BetterAgentError.fromCode("VALIDATION_FAILED", "Assistant messages do not support image or file inputs", { context: {
689
+ provider: "xai",
690
+ model: args.modelId
691
+ } }).at({ at: "xai.responses.map.input.assistantImage" });
692
+ if (part.type === "file") {
693
+ if (part.source.kind !== "provider-file") throw BetterAgentError.fromCode("VALIDATION_FAILED", "xAI file inputs currently require a provider-file source", { context: {
694
+ provider: "xai",
695
+ model: args.modelId,
696
+ sourceKind: part.source.kind
697
+ } }).at({ at: "xai.responses.map.input.fileSource" });
698
+ if (part.source.ref.provider !== "xai") throw BetterAgentError.fromCode("VALIDATION_FAILED", "xAI file inputs require a provider-file reference for provider=xai", { context: {
699
+ provider: "xai",
700
+ model: args.modelId,
701
+ sourceProvider: part.source.ref.provider
702
+ } }).at({ at: "xai.responses.map.input.fileProvider" });
703
+ return {
704
+ type: "input_file",
705
+ file_id: part.source.ref.id,
706
+ ...part.source.filename != null ? { filename: part.source.filename } : {}
707
+ };
708
+ }
709
+ if (part.type !== "image") throw BetterAgentError.fromCode("VALIDATION_FAILED", `Unsupported message part for xAI Responses: ${part.type}`, { context: {
710
+ provider: "xai",
711
+ model: args.modelId,
712
+ partType: part.type
713
+ } }).at({ at: "xai.responses.map.input.unsupportedPart" });
714
+ return {
715
+ type: "input_image",
716
+ detail: "auto",
717
+ image_url: part.source.kind === "url" ? part.source.url : `data:${part.source.mimeType};base64,${part.source.data}`
718
+ };
719
+ })
720
+ }];
721
+ }
722
+ const callArguments = "arguments" in item && typeof item.arguments === "string" ? item.arguments : "{}";
723
+ const call = {
724
+ type: "function_call",
725
+ call_id: item.callId,
726
+ name: item.name,
727
+ arguments: callArguments
728
+ };
729
+ if (item.result == null) return [call];
730
+ return [call, {
731
+ type: "function_call_output",
732
+ call_id: item.callId,
733
+ output: typeof item.result === "string" ? item.result : JSON.stringify(item.result),
734
+ status: item.isError === true ? "incomplete" : "completed"
735
+ }];
736
+ });
737
+ let text;
738
+ if ("structured_output" in o && o.structured_output) {
739
+ const out = o.structured_output;
740
+ const { name, strict = true } = out;
741
+ if (out.schema.type !== "object") return err(BetterAgentError.fromCode("VALIDATION_FAILED", "Structured output schema must be an object", { context: {
742
+ provider: "xai",
743
+ model: args.modelId
744
+ } }).at({ at: "xai.responses.map.structuredOutput" }));
745
+ text = { format: {
746
+ type: "json_schema",
747
+ name,
748
+ strict,
749
+ schema: out.schema
750
+ } };
751
+ }
752
+ const xaiTools = [];
753
+ const tools = ("tools" in o ? o.tools : []) ?? [];
754
+ if (tools.length) for (const tool of tools) {
755
+ if (isXAINativeToolDefinition(tool)) {
756
+ xaiTools.push(mapXAINativeToolToRequest(tool));
757
+ continue;
758
+ }
759
+ const callableTool = tool;
760
+ if (!callableTool || !isCallableToolDefinition(callableTool)) continue;
761
+ const parameters = callableTool[TOOL_JSON_SCHEMA];
762
+ if (parameters.type !== "object") return err(BetterAgentError.fromCode("VALIDATION_FAILED", "Tool parameters schema must be an object", { context: {
763
+ provider: "xai",
764
+ model: args.modelId
765
+ } }).at({ at: "xai.responses.map.tools" }));
766
+ xaiTools.push({
767
+ type: "function",
768
+ name: String(callableTool.name ?? ""),
769
+ description: typeof callableTool.description === "string" ? callableTool.description : null,
770
+ parameters,
771
+ strict: typeof callableTool.strict === "boolean" ? callableTool.strict : null
772
+ });
773
+ }
774
+ let xaiToolChoice;
775
+ if ("tools" in o && o.tools && "toolChoice" in o && o.toolChoice && o.toolChoice.type !== "auto") {
776
+ const tc = o.toolChoice;
777
+ if (tc.type === "none") xaiToolChoice = "none";
778
+ else if (tc.type === "required") xaiToolChoice = "required";
779
+ else if (tc.type === "tool") {
780
+ if (!xaiTools.length) return err(BetterAgentError.fromCode("VALIDATION_FAILED", "toolChoice=tool requires tools[] to be provided", { context: {
781
+ provider: "xai",
782
+ model: args.modelId
783
+ } }).at({ at: "xai.responses.map.toolChoice" }));
784
+ if (!xaiTools.some((t) => typeof t === "object" && t && "type" in t && t.type === "function" && "name" in t && t.name === tc.name)) return err(BetterAgentError.fromCode("VALIDATION_FAILED", `Requested tool not found: ${tc.name}`, { context: {
785
+ provider: "xai",
786
+ model: args.modelId
787
+ } }).at({ at: "xai.responses.map.toolChoice" }));
788
+ xaiToolChoice = {
789
+ type: "function",
790
+ name: tc.name
791
+ };
792
+ }
793
+ }
794
+ const request = {
795
+ ...extractPassthroughOptions(o, XAI_RESPONSE_KNOWN_KEYS),
796
+ model: args.modelId,
797
+ input,
798
+ ...omitNullish({
799
+ text,
800
+ tools: xaiTools.length ? xaiTools : void 0,
801
+ tool_choice: xaiToolChoice,
802
+ include: o.include,
803
+ instructions: raw.instructions,
804
+ metadata: o.metadata,
805
+ parallel_tool_calls: o.parallel_tool_calls,
806
+ previous_response_id: o.previous_response_id,
807
+ reasoning: o.reasoning,
808
+ search_parameters: o.search_parameters,
809
+ service_tier: o.service_tier,
810
+ store: o.store,
811
+ user: o.user
812
+ })
813
+ };
814
+ const responseOpts = o;
815
+ if (responseOpts.modalities === void 0 || responseOpts.modalities.includes("text")) {
816
+ if (responseOpts.max_output_tokens != null) request.max_output_tokens = responseOpts.max_output_tokens;
817
+ if (responseOpts.logprobs != null) request.logprobs = responseOpts.logprobs;
818
+ if (responseOpts.temperature != null) request.temperature = responseOpts.temperature;
819
+ if (responseOpts.top_logprobs != null) request.top_logprobs = responseOpts.top_logprobs;
820
+ if (responseOpts.top_p != null) request.top_p = responseOpts.top_p;
821
+ }
822
+ return ok(request);
823
+ } catch (e) {
824
+ return err(BetterAgentError.wrap({
825
+ err: e,
826
+ message: "Failed to map xAI Responses request",
827
+ opts: {
828
+ code: "INTERNAL",
829
+ context: {
830
+ provider: "xai",
831
+ model: args.modelId
832
+ }
833
+ }
834
+ }).at({ at: "xai.responses.mapToRequest" }));
835
+ }
836
+ }
837
+ function mapFromXAIResponsesResponse(response) {
838
+ const outputItems = [];
839
+ for (const item of response.output ?? []) {
840
+ if (!item || typeof item !== "object" || !("type" in item)) continue;
841
+ if (item.type === "message") {
842
+ const parts = Array.isArray(item.content) ? item.content.flatMap((part) => {
843
+ if (!part || typeof part !== "object" || !("type" in part)) return [];
844
+ const candidate = part;
845
+ if (candidate.type === "output_text" && typeof candidate.text === "string") return [{
846
+ type: "text",
847
+ text: candidate.text
848
+ }];
849
+ return [];
850
+ }) : [];
851
+ if (parts.length > 0) outputItems.push({
852
+ type: "message",
853
+ role: item.role ?? "assistant",
854
+ content: parts
855
+ });
856
+ continue;
857
+ }
858
+ if (item.type === "function_call" && typeof item.name === "string" && typeof item.call_id === "string") {
859
+ outputItems.push({
860
+ type: "tool-call",
861
+ name: item.name,
862
+ arguments: typeof item.arguments === "string" ? item.arguments : "{}",
863
+ callId: item.call_id
864
+ });
865
+ continue;
866
+ }
867
+ if (typeof item.type === "string" && item.type.endsWith("_call")) {
868
+ if (!("id" in item) || !(typeof item.id === "string" && item.id.length > 0)) continue;
869
+ outputItems.push({
870
+ type: "provider-tool-result",
871
+ name: item.type.slice(0, -5),
872
+ callId: item.id,
873
+ result: item
874
+ });
875
+ continue;
876
+ }
877
+ if (typeof item.type === "string" && item.type.endsWith("_call_output")) {
878
+ if (!("call_id" in item) || typeof item.call_id !== "string" || item.call_id.length === 0) continue;
879
+ outputItems.push({
880
+ type: "provider-tool-result",
881
+ name: item.type.slice(0, -12),
882
+ callId: item.call_id,
883
+ result: item
884
+ });
885
+ }
886
+ }
887
+ const inputTokens = response.usage?.input_tokens;
888
+ const outputTokens = response.usage?.output_tokens;
889
+ const usage = omitNullish({
890
+ inputTokens,
891
+ outputTokens,
892
+ totalTokens: typeof inputTokens === "number" && typeof outputTokens === "number" ? inputTokens + outputTokens : void 0,
893
+ reasoningTokens: response.usage?.output_tokens_details?.reasoning_tokens,
894
+ cachedInputTokens: response.usage?.input_tokens_details?.cached_tokens
895
+ });
896
+ const hasToolCalls = outputItems.some((item) => item.type === "tool-call" && "arguments" in item);
897
+ let finishReason;
898
+ const incompleteReason = response.incomplete_details?.reason;
899
+ if (incompleteReason === "max_output_tokens") finishReason = "length";
900
+ else if (incompleteReason === "content_filter") finishReason = "content-filter";
901
+ else if (incompleteReason) finishReason = "other";
902
+ else if (hasToolCalls) finishReason = "tool-calls";
903
+ else finishReason = "stop";
904
+ return {
905
+ output: outputItems,
906
+ finishReason,
907
+ usage,
908
+ response: { body: response }
909
+ };
910
+ }
911
+ function mapFromXAIResponsesStreamEvent(event, messageId) {
912
+ if (event.type === "response.reasoning_summary_part.added") return ok({
913
+ kind: "event",
914
+ event: {
915
+ type: Events.REASONING_MESSAGE_START,
916
+ messageId,
917
+ role: "assistant",
918
+ visibility: "summary",
919
+ provider: "xai",
920
+ timestamp: Date.now()
921
+ }
922
+ });
923
+ if (event.type === "response.reasoning_summary_text.delta") return ok({
924
+ kind: "event",
925
+ event: {
926
+ type: Events.REASONING_MESSAGE_CONTENT,
927
+ messageId,
928
+ visibility: "summary",
929
+ delta: event.delta ?? "",
930
+ provider: "xai",
931
+ timestamp: Date.now()
932
+ }
933
+ });
934
+ if (event.type === "response.reasoning_summary_text.done") return ok({
935
+ kind: "event",
936
+ event: {
937
+ type: Events.REASONING_MESSAGE_END,
938
+ messageId,
939
+ visibility: "summary",
940
+ provider: "xai",
941
+ timestamp: Date.now()
942
+ }
943
+ });
944
+ if (event.type === "response.reasoning_text.delta") return ok({
945
+ kind: "event",
946
+ event: {
947
+ type: Events.REASONING_MESSAGE_CONTENT,
948
+ messageId,
949
+ visibility: "full",
950
+ delta: event.delta ?? "",
951
+ provider: "xai",
952
+ timestamp: Date.now()
953
+ }
954
+ });
955
+ if (event.type === "response.reasoning_text.done") return ok({
956
+ kind: "event",
957
+ event: {
958
+ type: Events.REASONING_MESSAGE_END,
959
+ messageId,
960
+ visibility: "full",
961
+ provider: "xai",
962
+ timestamp: Date.now()
963
+ }
964
+ });
965
+ if (event.type === "response.output_item.added") {
966
+ if (event.item?.type === "message") return ok({
967
+ kind: "event",
968
+ event: {
969
+ type: Events.TEXT_MESSAGE_START,
970
+ messageId,
971
+ role: "assistant",
972
+ timestamp: Date.now()
973
+ }
974
+ });
975
+ if (event.item?.type === "function_call") {
976
+ const toolCallId = typeof event.item.call_id === "string" && event.item.call_id.length > 0 ? event.item.call_id : event.item.id;
977
+ if (!(typeof toolCallId === "string" && toolCallId.length > 0)) return ok(null);
978
+ return ok({
979
+ kind: "event",
980
+ event: {
981
+ type: Events.TOOL_CALL_START,
982
+ toolCallId,
983
+ toolCallName: event.item.name ?? "",
984
+ parentMessageId: messageId,
985
+ timestamp: Date.now()
986
+ }
987
+ });
988
+ }
989
+ if (typeof event.item?.type === "string" && event.item.type.endsWith("_call") && event.item.type !== "function_call" && typeof event.item.id === "string" && event.item.id.length > 0) return ok({
990
+ kind: "event",
991
+ event: {
992
+ type: Events.TOOL_CALL_START,
993
+ toolCallId: event.item.id,
994
+ toolCallName: event.item.type.slice(0, -5),
995
+ parentMessageId: messageId,
996
+ timestamp: Date.now()
997
+ }
998
+ });
999
+ }
1000
+ if (event.type === "response.output_text.delta") return ok({
1001
+ kind: "event",
1002
+ event: {
1003
+ type: Events.TEXT_MESSAGE_CONTENT,
1004
+ messageId,
1005
+ delta: event.delta ?? "",
1006
+ timestamp: Date.now()
1007
+ }
1008
+ });
1009
+ if (event.type === "response.output_text.done") return ok({
1010
+ kind: "event",
1011
+ event: {
1012
+ type: Events.TEXT_MESSAGE_END,
1013
+ messageId,
1014
+ timestamp: Date.now()
1015
+ }
1016
+ });
1017
+ if (event.type === "response.function_call_arguments.delta") {
1018
+ const toolCallId = typeof event.call_id === "string" && event.call_id.length > 0 ? event.call_id : event.item_id;
1019
+ if (!(typeof toolCallId === "string" && toolCallId.length > 0)) return ok(null);
1020
+ return ok({
1021
+ kind: "event",
1022
+ event: {
1023
+ type: Events.TOOL_CALL_ARGS,
1024
+ parentMessageId: messageId,
1025
+ toolCallId,
1026
+ toolCallName: "unknown",
1027
+ delta: event.delta ?? "",
1028
+ timestamp: Date.now()
1029
+ }
1030
+ });
1031
+ }
1032
+ if (event.type === "response.function_call_arguments.done") {
1033
+ const toolCallId = typeof event.call_id === "string" && event.call_id.length > 0 ? event.call_id : event.item_id;
1034
+ if (!(typeof toolCallId === "string" && toolCallId.length > 0)) return ok(null);
1035
+ return ok({
1036
+ kind: "event",
1037
+ event: {
1038
+ type: Events.TOOL_CALL_END,
1039
+ parentMessageId: messageId,
1040
+ toolCallId,
1041
+ toolCallName: "unknown",
1042
+ timestamp: Date.now()
1043
+ }
1044
+ });
1045
+ }
1046
+ if (event.type === "response.web_search_call.in_progress" || event.type === "response.web_search_call.searching" || event.type === "response.web_search_call.completed" || event.type === "response.x_search_call.in_progress" || event.type === "response.x_search_call.searching" || event.type === "response.x_search_call.completed" || event.type === "response.file_search_call.in_progress" || event.type === "response.file_search_call.searching" || event.type === "response.file_search_call.completed" || event.type === "response.code_interpreter_call.in_progress" || event.type === "response.code_interpreter_call.interpreting" || event.type === "response.code_interpreter_call.completed" || event.type === "response.code_execution_call.in_progress" || event.type === "response.code_execution_call.interpreting" || event.type === "response.code_execution_call.completed" || event.type === "response.mcp_call.in_progress" || event.type === "response.mcp_call.completed" || event.type === "response.mcp_call.failed" || event.type === "response.mcp_list_tools.in_progress" || event.type === "response.mcp_list_tools.completed" || event.type === "response.mcp_list_tools.failed") {
1047
+ const fullType = event.type.slice(9);
1048
+ const dotIndex = fullType.lastIndexOf(".");
1049
+ const toolSegment = dotIndex >= 0 ? fullType.slice(0, dotIndex) : fullType;
1050
+ const status = dotIndex >= 0 ? fullType.slice(dotIndex + 1) : "unknown";
1051
+ const tool = toolSegment.endsWith("_call") ? toolSegment.slice(0, -5) : toolSegment;
1052
+ return ok({
1053
+ kind: "event",
1054
+ event: {
1055
+ type: Events.DATA_PART,
1056
+ ...typeof event.item_id === "string" ? { id: event.item_id } : {},
1057
+ data: {
1058
+ endpoint: "responses",
1059
+ tool,
1060
+ status,
1061
+ raw: event
1062
+ },
1063
+ timestamp: Date.now()
1064
+ }
1065
+ });
1066
+ }
1067
+ if (event.type === "response.output_item.done") {
1068
+ if (typeof event.item?.type === "string" && event.item.type.endsWith("_call") && event.item.type !== "function_call" && typeof event.item.id === "string" && event.item.id.length > 0) return ok({
1069
+ kind: "event",
1070
+ event: {
1071
+ type: Events.TOOL_CALL_RESULT,
1072
+ parentMessageId: messageId,
1073
+ toolCallId: event.item.id,
1074
+ toolCallName: event.item.type.slice(0, -5),
1075
+ result: event.item,
1076
+ timestamp: Date.now()
1077
+ }
1078
+ });
1079
+ }
1080
+ if (event.type === "response.completed") return ok({
1081
+ kind: "final",
1082
+ response: mapFromXAIResponsesResponse(event.response)
1083
+ });
1084
+ if (event.type === "error") return err(BetterAgentError.fromCode("UPSTREAM_FAILED", event.message ?? "xAI streaming error", { context: {
1085
+ provider: "xai",
1086
+ upstreamCode: "STREAM_ERROR",
1087
+ raw: event
1088
+ } }).at({ at: "xai.responses.stream.event" }));
1089
+ return ok(null);
1090
+ }
1091
+
1092
+ //#endregion
1093
+ //#region src/xai/responses/model.ts
1094
+ const XAI_RESPONSE_CAPS = {
1095
+ inputModalities: {
1096
+ text: true,
1097
+ image: true,
1098
+ file: true
1099
+ },
1100
+ inputShape: "chat",
1101
+ replayMode: "multi_turn",
1102
+ supportsInstruction: true,
1103
+ outputModalities: { text: { options: {} } },
1104
+ tools: true,
1105
+ structured_output: true,
1106
+ additionalSupportedRoles: ["developer"]
1107
+ };
1108
+ const createDeferred = () => {
1109
+ let resolve;
1110
+ let reject;
1111
+ return {
1112
+ promise: new Promise((res, rej) => {
1113
+ resolve = res;
1114
+ reject = rej;
1115
+ }),
1116
+ resolve,
1117
+ reject
1118
+ };
1119
+ };
1120
+ const createXAIResponsesModel = (modelId, client) => {
1121
+ const doGenerate = async (options, ctx) => {
1122
+ const requestBodyResult = mapToXAIResponsesRequest({
1123
+ modelId,
1124
+ options
1125
+ });
1126
+ if (requestBodyResult.isErr()) return err(requestBodyResult.error.at({ at: "xai.generate.mapRequest" }));
1127
+ const raw = await client.responses.create(requestBodyResult.value, { signal: ctx.signal ?? null });
1128
+ if (raw.isErr()) return err(raw.error.at({ at: "xai.generate.http" }));
1129
+ return ok({ response: {
1130
+ ...mapFromXAIResponsesResponse(raw.value),
1131
+ request: { body: requestBodyResult.value }
1132
+ } });
1133
+ };
1134
+ const doGenerateStream = async (options, ctx) => {
1135
+ const requestBodyResult = mapToXAIResponsesRequest({
1136
+ modelId,
1137
+ options
1138
+ });
1139
+ if (requestBodyResult.isErr()) return err(requestBodyResult.error.at({ at: "xai.generateStream.mapRequest" }));
1140
+ const streamResult = await client.responses.stream(requestBodyResult.value, { signal: ctx.signal ?? null });
1141
+ if (streamResult.isErr()) return err(streamResult.error.at({ at: "xai.generateStream.http" }));
1142
+ const { promise: final, resolve: resolveFinal, reject: rejectFinal } = createDeferred();
1143
+ return ok({
1144
+ events: (async function* () {
1145
+ const messageId = ctx.generateMessageId();
1146
+ let sawFinal = false;
1147
+ try {
1148
+ for await (const raw of streamResult.value) {
1149
+ if (raw.isErr()) {
1150
+ rejectFinal(raw.error);
1151
+ yield err(raw.error);
1152
+ return;
1153
+ }
1154
+ const mapped = mapFromXAIResponsesStreamEvent(raw.value, messageId);
1155
+ if (mapped.isErr()) {
1156
+ const error = mapped.error.at({ at: "xai.generateStream.mapEvent" });
1157
+ rejectFinal(error);
1158
+ yield err(error);
1159
+ return;
1160
+ }
1161
+ const value = mapped.value;
1162
+ if (!value) continue;
1163
+ if (value.kind === "final") {
1164
+ sawFinal = true;
1165
+ resolveFinal(value.response);
1166
+ continue;
1167
+ }
1168
+ yield ok(value.event);
1169
+ }
1170
+ } finally {
1171
+ if (!sawFinal) rejectFinal(BetterAgentError.fromCode("UPSTREAM_FAILED", "xAI stream ended without a final response event.", { context: {
1172
+ provider: "xai",
1173
+ model: String(modelId)
1174
+ } }).at({ at: "xai.generateStream.final" }));
1175
+ }
1176
+ })(),
1177
+ final
1178
+ });
1179
+ };
1180
+ return {
1181
+ providerId: "xai",
1182
+ modelId,
1183
+ caps: XAI_RESPONSE_CAPS,
1184
+ doGenerate,
1185
+ doGenerateStream
1186
+ };
1187
+ };
1188
+
1189
+ //#endregion
1190
+ //#region src/xai/shared/schemas.ts
1191
+ const XAI_RESPONSE_MODEL_NAMES = [
1192
+ "grok-3",
1193
+ "grok-3-latest",
1194
+ "grok-3-beta",
1195
+ "grok-3-fast",
1196
+ "grok-3-fast-latest",
1197
+ "grok-3-fast-beta",
1198
+ "grok-3-mini",
1199
+ "grok-4",
1200
+ "grok-4-1-fast-reasoning",
1201
+ "grok-4.20-beta-latest-non-reasoning",
1202
+ "grok-4.20-multi-agent-beta-0309",
1203
+ "grok-code-fast-1"
1204
+ ];
1205
+ const XAI_IMAGE_MODEL_NAMES = ["grok-imagine-image"];
1206
+ const XAIResponseModels = z.enum(XAI_RESPONSE_MODEL_NAMES).describe("Current documented xAI response model names. For the latest team-specific availability, also check <https://console.x.ai/team/default/models> and <https://docs.x.ai/docs/models>.");
1207
+ const XAIImageModels = z.enum(XAI_IMAGE_MODEL_NAMES).describe("Current documented xAI image model names. For the latest team-specific availability, also check <https://console.x.ai/team/default/models> and <https://docs.x.ai/docs/models>.");
1208
+ const XAI_MODEL_KINDS = {
1209
+ "grok-3": "text",
1210
+ "grok-3-latest": "text",
1211
+ "grok-3-beta": "text",
1212
+ "grok-3-fast": "text",
1213
+ "grok-3-fast-latest": "text",
1214
+ "grok-3-fast-beta": "text",
1215
+ "grok-3-mini": "text",
1216
+ "grok-4": "text",
1217
+ "grok-4-1-fast-reasoning": "text",
1218
+ "grok-4.20-beta-latest-non-reasoning": "text",
1219
+ "grok-4.20-multi-agent-beta-0309": "text",
1220
+ "grok-code-fast-1": "text",
1221
+ "grok-imagine-image": "image"
1222
+ };
1223
+ const getXAIModelKind = (modelId) => XAI_MODEL_KINDS[modelId];
1224
+ const XAIFileObjectSchema = z.object({
1225
+ id: z.string().describe("Unique file identifier."),
1226
+ object: z.string().optional().describe("Object type, typically `file`."),
1227
+ bytes: z.number().int().nonnegative().optional().describe("File size in bytes."),
1228
+ created_at: z.number().int().optional().describe("Unix timestamp when the file was created."),
1229
+ expires_at: z.number().int().nullish().describe("Optional expiration time."),
1230
+ filename: z.string().optional().describe("Original file name."),
1231
+ purpose: z.string().optional().describe("Declared file purpose."),
1232
+ status: z.string().optional().describe("Provider-side processing status."),
1233
+ status_details: z.any().optional().describe("Provider-side status details.")
1234
+ }).passthrough().describe("xAI file object.");
1235
+ z.object({
1236
+ object: z.string().optional().describe("List object type."),
1237
+ data: z.array(XAIFileObjectSchema).describe("Files returned by the provider."),
1238
+ first_id: z.string().nullish().optional().describe("First file id in the page."),
1239
+ last_id: z.string().nullish().optional().describe("Last file id in the page."),
1240
+ has_more: z.boolean().optional().describe("Whether additional pages are available.")
1241
+ }).passthrough().describe("xAI files list response.");
1242
+ z.object({
1243
+ id: z.string().describe("Deleted file identifier."),
1244
+ object: z.string().optional().describe("Delete response object type."),
1245
+ deleted: z.boolean().describe("Whether the file was deleted.")
1246
+ }).passthrough().describe("xAI delete file response.");
1247
+
1248
+ //#endregion
1249
+ //#region src/xai/models/index.ts
1250
+ function createXAIModel(modelId, client) {
1251
+ if (getXAIModelKind(modelId) === "image") return createXAIImagesModel(modelId, client);
1252
+ return createXAIResponsesModel(modelId, client);
1253
+ }
1254
+
1255
+ //#endregion
1256
+ //#region src/xai/provider.ts
1257
+ const createXAI = (config) => {
1258
+ const httpClient = createXAIClient(config);
1259
+ return {
1260
+ id: "xai",
1261
+ tools: createXAINativeToolBuilders(),
1262
+ files: httpClient.files,
1263
+ model(modelId) {
1264
+ return createXAIModel(modelId, httpClient);
1265
+ },
1266
+ text(modelId) {
1267
+ return createXAIResponsesModel(modelId, httpClient);
1268
+ },
1269
+ image(modelId) {
1270
+ return createXAIImagesModel(modelId, httpClient);
1271
+ }
1272
+ };
1273
+ };
1274
+
1275
+ //#endregion
1276
+ export { createXAI };
1277
+ //# sourceMappingURL=index.mjs.map