@ai-sdk/xai 0.0.0-1c33ba03-20260114162300 → 0.0.0-4115c213-20260122152721

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/xai",
3
- "version": "0.0.0-1c33ba03-20260114162300",
3
+ "version": "0.0.0-4115c213-20260122152721",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -8,9 +8,18 @@
8
8
  "types": "./dist/index.d.ts",
9
9
  "files": [
10
10
  "dist/**/*",
11
+ "docs/**/*",
12
+ "src",
13
+ "!src/**/*.test.ts",
14
+ "!src/**/*.test-d.ts",
15
+ "!src/**/__snapshots__",
16
+ "!src/**/__fixtures__",
11
17
  "CHANGELOG.md",
12
18
  "README.md"
13
19
  ],
20
+ "directories": {
21
+ "doc": "./docs"
22
+ },
14
23
  "exports": {
15
24
  "./package.json": "./package.json",
16
25
  ".": {
@@ -20,16 +29,16 @@
20
29
  }
21
30
  },
22
31
  "dependencies": {
23
- "@ai-sdk/openai-compatible": "0.0.0-1c33ba03-20260114162300",
24
- "@ai-sdk/provider": "3.0.3",
25
- "@ai-sdk/provider-utils": "0.0.0-1c33ba03-20260114162300"
32
+ "@ai-sdk/openai-compatible": "0.0.0-4115c213-20260122152721",
33
+ "@ai-sdk/provider": "0.0.0-4115c213-20260122152721",
34
+ "@ai-sdk/provider-utils": "0.0.0-4115c213-20260122152721"
26
35
  },
27
36
  "devDependencies": {
28
37
  "@types/node": "20.17.24",
29
38
  "tsup": "^8",
30
39
  "typescript": "5.8.3",
31
40
  "zod": "3.25.76",
32
- "@ai-sdk/test-server": "1.0.1",
41
+ "@ai-sdk/test-server": "0.0.0-4115c213-20260122152721",
33
42
  "@vercel/ai-tsconfig": "0.0.0"
34
43
  },
35
44
  "peerDependencies": {
@@ -55,7 +64,7 @@
55
64
  "scripts": {
56
65
  "build": "pnpm clean && tsup --tsconfig tsconfig.build.json",
57
66
  "build:watch": "pnpm clean && tsup --watch",
58
- "clean": "del-cli dist *.tsbuildinfo",
67
+ "clean": "del-cli dist docs *.tsbuildinfo",
59
68
  "lint": "eslint \"./**/*.ts*\"",
60
69
  "type-check": "tsc --build",
61
70
  "prettier-check": "prettier --check \"./**/*.ts*\"",
@@ -0,0 +1,142 @@
1
+ import {
2
+ SharedV3Warning,
3
+ LanguageModelV3Prompt,
4
+ UnsupportedFunctionalityError,
5
+ } from '@ai-sdk/provider';
6
+ import { convertToBase64 } from '@ai-sdk/provider-utils';
7
+ import { XaiChatPrompt } from './xai-chat-prompt';
8
+
9
+ export function convertToXaiChatMessages(prompt: LanguageModelV3Prompt): {
10
+ messages: XaiChatPrompt;
11
+ warnings: Array<SharedV3Warning>;
12
+ } {
13
+ const messages: XaiChatPrompt = [];
14
+ const warnings: Array<SharedV3Warning> = [];
15
+
16
+ for (const { role, content } of prompt) {
17
+ switch (role) {
18
+ case 'system': {
19
+ messages.push({ role: 'system', content });
20
+ break;
21
+ }
22
+
23
+ case 'user': {
24
+ if (content.length === 1 && content[0].type === 'text') {
25
+ messages.push({ role: 'user', content: content[0].text });
26
+ break;
27
+ }
28
+
29
+ messages.push({
30
+ role: 'user',
31
+ content: content.map(part => {
32
+ switch (part.type) {
33
+ case 'text': {
34
+ return { type: 'text', text: part.text };
35
+ }
36
+ case 'file': {
37
+ if (part.mediaType.startsWith('image/')) {
38
+ const mediaType =
39
+ part.mediaType === 'image/*'
40
+ ? 'image/jpeg'
41
+ : part.mediaType;
42
+
43
+ return {
44
+ type: 'image_url',
45
+ image_url: {
46
+ url:
47
+ part.data instanceof URL
48
+ ? part.data.toString()
49
+ : `data:${mediaType};base64,${convertToBase64(part.data)}`,
50
+ },
51
+ };
52
+ } else {
53
+ throw new UnsupportedFunctionalityError({
54
+ functionality: `file part media type ${part.mediaType}`,
55
+ });
56
+ }
57
+ }
58
+ }
59
+ }),
60
+ });
61
+
62
+ break;
63
+ }
64
+
65
+ case 'assistant': {
66
+ let text = '';
67
+ const toolCalls: Array<{
68
+ id: string;
69
+ type: 'function';
70
+ function: { name: string; arguments: string };
71
+ }> = [];
72
+
73
+ for (const part of content) {
74
+ switch (part.type) {
75
+ case 'text': {
76
+ text += part.text;
77
+ break;
78
+ }
79
+ case 'tool-call': {
80
+ toolCalls.push({
81
+ id: part.toolCallId,
82
+ type: 'function',
83
+ function: {
84
+ name: part.toolName,
85
+ arguments: JSON.stringify(part.input),
86
+ },
87
+ });
88
+ break;
89
+ }
90
+ }
91
+ }
92
+
93
+ messages.push({
94
+ role: 'assistant',
95
+ content: text,
96
+ tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
97
+ });
98
+
99
+ break;
100
+ }
101
+
102
+ case 'tool': {
103
+ for (const toolResponse of content) {
104
+ if (toolResponse.type === 'tool-approval-response') {
105
+ continue;
106
+ }
107
+ const output = toolResponse.output;
108
+
109
+ let contentValue: string;
110
+ switch (output.type) {
111
+ case 'text':
112
+ case 'error-text':
113
+ contentValue = output.value;
114
+ break;
115
+ case 'execution-denied':
116
+ contentValue = output.reason ?? 'Tool execution denied.';
117
+ break;
118
+ case 'content':
119
+ case 'json':
120
+ case 'error-json':
121
+ contentValue = JSON.stringify(output.value);
122
+ break;
123
+ }
124
+
125
+ messages.push({
126
+ role: 'tool',
127
+ tool_call_id: toolResponse.toolCallId,
128
+ content: contentValue,
129
+ });
130
+ }
131
+ break;
132
+ }
133
+
134
+ default: {
135
+ const _exhaustiveCheck: never = role;
136
+ throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
137
+ }
138
+ }
139
+ }
140
+
141
+ return { messages, warnings };
142
+ }
@@ -0,0 +1,23 @@
1
+ import { LanguageModelV3Usage } from '@ai-sdk/provider';
2
+ import { XaiChatUsage } from './xai-chat-language-model';
3
+
4
+ export function convertXaiChatUsage(usage: XaiChatUsage): LanguageModelV3Usage {
5
+ const cacheReadTokens = usage.prompt_tokens_details?.cached_tokens ?? 0;
6
+ const reasoningTokens =
7
+ usage.completion_tokens_details?.reasoning_tokens ?? 0;
8
+
9
+ return {
10
+ inputTokens: {
11
+ total: usage.prompt_tokens,
12
+ noCache: usage.prompt_tokens - cacheReadTokens,
13
+ cacheRead: cacheReadTokens,
14
+ cacheWrite: undefined,
15
+ },
16
+ outputTokens: {
17
+ total: usage.completion_tokens,
18
+ text: usage.completion_tokens - reasoningTokens,
19
+ reasoning: reasoningTokens,
20
+ },
21
+ raw: usage,
22
+ };
23
+ }
@@ -0,0 +1,19 @@
1
+ export function getResponseMetadata({
2
+ id,
3
+ model,
4
+ created,
5
+ created_at,
6
+ }: {
7
+ id?: string | undefined | null;
8
+ created?: number | undefined | null;
9
+ created_at?: number | undefined | null;
10
+ model?: string | undefined | null;
11
+ }) {
12
+ const unixTime = created ?? created_at;
13
+
14
+ return {
15
+ id: id ?? undefined,
16
+ modelId: model ?? undefined,
17
+ timestamp: unixTime != null ? new Date(unixTime * 1000) : undefined,
18
+ };
19
+ }
package/src/index.ts ADDED
@@ -0,0 +1,14 @@
1
+ export type { XaiProviderOptions } from './xai-chat-options';
2
+ export type { XaiErrorData } from './xai-error';
3
+ export type { XaiResponsesProviderOptions } from './responses/xai-responses-options';
4
+ export { createXai, xai } from './xai-provider';
5
+ export type { XaiProvider, XaiProviderSettings } from './xai-provider';
6
+ export {
7
+ codeExecution,
8
+ viewImage,
9
+ viewXVideo,
10
+ webSearch,
11
+ xSearch,
12
+ xaiTools,
13
+ } from './tool';
14
+ export { VERSION } from './version';
@@ -0,0 +1,19 @@
1
+ import { LanguageModelV3FinishReason } from '@ai-sdk/provider';
2
+
3
+ export function mapXaiFinishReason(
4
+ finishReason: string | null | undefined,
5
+ ): LanguageModelV3FinishReason['unified'] {
6
+ switch (finishReason) {
7
+ case 'stop':
8
+ return 'stop';
9
+ case 'length':
10
+ return 'length';
11
+ case 'tool_calls':
12
+ case 'function_call':
13
+ return 'tool-calls';
14
+ case 'content_filter':
15
+ return 'content-filter';
16
+ default:
17
+ return 'other';
18
+ }
19
+ }
@@ -0,0 +1,206 @@
1
+ import {
2
+ SharedV3Warning,
3
+ LanguageModelV3Message,
4
+ UnsupportedFunctionalityError,
5
+ } from '@ai-sdk/provider';
6
+ import { convertToBase64 } from '@ai-sdk/provider-utils';
7
+ import {
8
+ XaiResponsesInput,
9
+ XaiResponsesUserMessageContentPart,
10
+ } from './xai-responses-api';
11
+
12
+ export async function convertToXaiResponsesInput({
13
+ prompt,
14
+ }: {
15
+ prompt: LanguageModelV3Message[];
16
+ store?: boolean;
17
+ }): Promise<{
18
+ input: XaiResponsesInput;
19
+ inputWarnings: SharedV3Warning[];
20
+ }> {
21
+ const input: XaiResponsesInput = [];
22
+ const inputWarnings: SharedV3Warning[] = [];
23
+
24
+ for (const message of prompt) {
25
+ switch (message.role) {
26
+ case 'system': {
27
+ input.push({
28
+ role: 'system',
29
+ content: message.content,
30
+ });
31
+ break;
32
+ }
33
+
34
+ case 'user': {
35
+ const contentParts: XaiResponsesUserMessageContentPart[] = [];
36
+
37
+ for (const block of message.content) {
38
+ switch (block.type) {
39
+ case 'text': {
40
+ contentParts.push({ type: 'input_text', text: block.text });
41
+ break;
42
+ }
43
+
44
+ case 'file': {
45
+ if (block.mediaType.startsWith('image/')) {
46
+ const mediaType =
47
+ block.mediaType === 'image/*'
48
+ ? 'image/jpeg'
49
+ : block.mediaType;
50
+
51
+ const imageUrl =
52
+ block.data instanceof URL
53
+ ? block.data.toString()
54
+ : `data:${mediaType};base64,${convertToBase64(block.data)}`;
55
+
56
+ contentParts.push({ type: 'input_image', image_url: imageUrl });
57
+ } else {
58
+ throw new UnsupportedFunctionalityError({
59
+ functionality: `file part media type ${block.mediaType}`,
60
+ });
61
+ }
62
+ break;
63
+ }
64
+
65
+ default: {
66
+ const _exhaustiveCheck: never = block;
67
+ inputWarnings.push({
68
+ type: 'other',
69
+ message:
70
+ 'xAI Responses API does not support this content type in user messages',
71
+ });
72
+ }
73
+ }
74
+ }
75
+
76
+ input.push({
77
+ role: 'user',
78
+ content: contentParts,
79
+ });
80
+ break;
81
+ }
82
+
83
+ case 'assistant': {
84
+ for (const part of message.content) {
85
+ switch (part.type) {
86
+ case 'text': {
87
+ const id =
88
+ typeof part.providerOptions?.xai?.itemId === 'string'
89
+ ? part.providerOptions.xai.itemId
90
+ : undefined;
91
+
92
+ input.push({
93
+ role: 'assistant',
94
+ content: part.text,
95
+ id,
96
+ });
97
+
98
+ break;
99
+ }
100
+
101
+ case 'tool-call': {
102
+ if (part.providerExecuted) {
103
+ break;
104
+ }
105
+
106
+ const id =
107
+ typeof part.providerOptions?.xai?.itemId === 'string'
108
+ ? part.providerOptions.xai.itemId
109
+ : undefined;
110
+
111
+ input.push({
112
+ type: 'function_call',
113
+ id: id ?? part.toolCallId,
114
+ call_id: part.toolCallId,
115
+ name: part.toolName,
116
+ arguments: JSON.stringify(part.input),
117
+ status: 'completed',
118
+ });
119
+ break;
120
+ }
121
+
122
+ case 'tool-result': {
123
+ break;
124
+ }
125
+
126
+ case 'reasoning':
127
+ case 'file': {
128
+ inputWarnings.push({
129
+ type: 'other',
130
+ message: `xAI Responses API does not support ${part.type} in assistant messages`,
131
+ });
132
+ break;
133
+ }
134
+
135
+ default: {
136
+ const _exhaustiveCheck: never = part;
137
+ inputWarnings.push({
138
+ type: 'other',
139
+ message:
140
+ 'xAI Responses API does not support this content type in assistant messages',
141
+ });
142
+ }
143
+ }
144
+ }
145
+
146
+ break;
147
+ }
148
+
149
+ case 'tool': {
150
+ for (const part of message.content) {
151
+ if (part.type === 'tool-approval-response') {
152
+ continue;
153
+ }
154
+ const output = part.output;
155
+
156
+ let outputValue: string;
157
+ switch (output.type) {
158
+ case 'text':
159
+ case 'error-text':
160
+ outputValue = output.value;
161
+ break;
162
+ case 'execution-denied':
163
+ outputValue = output.reason ?? 'tool execution denied';
164
+ break;
165
+ case 'json':
166
+ case 'error-json':
167
+ outputValue = JSON.stringify(output.value);
168
+ break;
169
+ case 'content':
170
+ outputValue = output.value
171
+ .map(item => {
172
+ if (item.type === 'text') {
173
+ return item.text;
174
+ }
175
+ return '';
176
+ })
177
+ .join('');
178
+ break;
179
+ default: {
180
+ const _exhaustiveCheck: never = output;
181
+ outputValue = '';
182
+ }
183
+ }
184
+
185
+ input.push({
186
+ type: 'function_call_output',
187
+ call_id: part.toolCallId,
188
+ output: outputValue,
189
+ });
190
+ }
191
+
192
+ break;
193
+ }
194
+
195
+ default: {
196
+ const _exhaustiveCheck: never = message;
197
+ inputWarnings.push({
198
+ type: 'other',
199
+ message: 'unsupported message role',
200
+ });
201
+ }
202
+ }
203
+ }
204
+
205
+ return { input, inputWarnings };
206
+ }
@@ -0,0 +1,24 @@
1
+ import { LanguageModelV3Usage } from '@ai-sdk/provider';
2
+ import { XaiResponsesUsage } from './xai-responses-api';
3
+
4
+ export function convertXaiResponsesUsage(
5
+ usage: XaiResponsesUsage,
6
+ ): LanguageModelV3Usage {
7
+ const cacheReadTokens = usage.input_tokens_details?.cached_tokens ?? 0;
8
+ const reasoningTokens = usage.output_tokens_details?.reasoning_tokens ?? 0;
9
+
10
+ return {
11
+ inputTokens: {
12
+ total: usage.input_tokens,
13
+ noCache: usage.input_tokens - cacheReadTokens,
14
+ cacheRead: cacheReadTokens,
15
+ cacheWrite: undefined,
16
+ },
17
+ outputTokens: {
18
+ total: usage.output_tokens,
19
+ text: usage.output_tokens - reasoningTokens,
20
+ reasoning: reasoningTokens,
21
+ },
22
+ raw: usage,
23
+ };
24
+ }
@@ -0,0 +1,20 @@
1
+ import { LanguageModelV3FinishReason } from '@ai-sdk/provider';
2
+
3
+ export function mapXaiResponsesFinishReason(
4
+ finishReason: string | null | undefined,
5
+ ): LanguageModelV3FinishReason['unified'] {
6
+ switch (finishReason) {
7
+ case 'stop':
8
+ case 'completed':
9
+ return 'stop';
10
+ case 'length':
11
+ return 'length';
12
+ case 'tool_calls':
13
+ case 'function_call':
14
+ return 'tool-calls';
15
+ case 'content_filter':
16
+ return 'content-filter';
17
+ default:
18
+ return 'other';
19
+ }
20
+ }