@ai-sdk/zai 0.0.0 → 1.0.2

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,252 @@
1
+ import { OpenAICompatibleChatLanguageModel } from '@ai-sdk/openai-compatible';
2
+ import type {
3
+ LanguageModelV2,
4
+ LanguageModelV2CallOptions,
5
+ LanguageModelV2CallWarning,
6
+ LanguageModelV2FinishReason,
7
+ LanguageModelV2StreamPart,
8
+ } from '@ai-sdk/provider';
9
+ import {
10
+ parseProviderOptions,
11
+ type FetchFunction,
12
+ } from '@ai-sdk/provider-utils';
13
+ import type { ZaiChatModelId } from './zai-chat-options';
14
+ import { zaiLanguageModelChatOptions } from './zai-chat-language-model-options';
15
+ import { zaiErrorStructure } from './zai-error';
16
+
17
+ export type ZaiChatConfig = {
18
+ provider: string;
19
+ baseURL: string;
20
+ headers?:
21
+ | Record<string, string | undefined>
22
+ | (() => Record<string, string | undefined>);
23
+ fetch?: FetchFunction;
24
+ };
25
+
26
+ function transformZaiRequestBody(
27
+ args: Record<string, any>,
28
+ ): Record<string, any> {
29
+ const {
30
+ doSample,
31
+ frequency_penalty: _frequencyPenalty,
32
+ presence_penalty: _presencePenalty,
33
+ requestId,
34
+ seed: _seed,
35
+ thinking,
36
+ toolStream,
37
+ user: _user,
38
+ userId,
39
+ verbosity: _verbosity,
40
+ ...restArgs
41
+ } = args;
42
+
43
+ return {
44
+ ...restArgs,
45
+ ...(doSample !== undefined && { do_sample: doSample }),
46
+ ...(thinking !== undefined && {
47
+ thinking: {
48
+ ...(thinking.type !== undefined && { type: thinking.type }),
49
+ ...(thinking.clearThinking !== undefined && {
50
+ clear_thinking: thinking.clearThinking,
51
+ }),
52
+ },
53
+ }),
54
+ ...(toolStream !== undefined && { tool_stream: toolStream }),
55
+ ...(requestId !== undefined && { request_id: requestId }),
56
+ ...(userId !== undefined && { user_id: userId }),
57
+ };
58
+ }
59
+
60
+ function mapZaiFinishReason(
61
+ finishReason: LanguageModelV2FinishReason,
62
+ rawFinishReason: string | undefined,
63
+ ): LanguageModelV2FinishReason {
64
+ switch (rawFinishReason) {
65
+ case 'sensitive':
66
+ return 'content-filter';
67
+ case 'model_context_window_exceeded':
68
+ return 'length';
69
+ case 'network_error':
70
+ return 'error';
71
+ default:
72
+ return finishReason;
73
+ }
74
+ }
75
+
76
+ function getRawFinishReason(responseBody: unknown): string | undefined {
77
+ if (responseBody == null || typeof responseBody !== 'object') {
78
+ return undefined;
79
+ }
80
+
81
+ const choices = (responseBody as { choices?: unknown }).choices;
82
+ if (!Array.isArray(choices) || choices.length === 0) {
83
+ return undefined;
84
+ }
85
+
86
+ const choice = choices[0];
87
+ if (choice == null || typeof choice !== 'object') {
88
+ return undefined;
89
+ }
90
+
91
+ const finishReason = (choice as { finish_reason?: unknown }).finish_reason;
92
+ return typeof finishReason === 'string' ? finishReason : undefined;
93
+ }
94
+
95
+ export class ZaiChatLanguageModel
96
+ extends OpenAICompatibleChatLanguageModel
97
+ implements LanguageModelV2
98
+ {
99
+ constructor(modelId: ZaiChatModelId, config: ZaiChatConfig) {
100
+ const headers = config.headers;
101
+
102
+ super(modelId, {
103
+ provider: config.provider,
104
+ url: ({ path }) => `${config.baseURL}${path}`,
105
+ headers: () =>
106
+ headers == null
107
+ ? {}
108
+ : typeof headers === 'function'
109
+ ? headers()
110
+ : headers,
111
+ fetch: config.fetch,
112
+ errorStructure: zaiErrorStructure,
113
+ transformRequestBody: transformZaiRequestBody,
114
+ supportedUrls: () => ({
115
+ 'image/*': [/^https?:\/\//],
116
+ 'video/*': [/^https?:\/\//],
117
+ }),
118
+ });
119
+ }
120
+
121
+ private async prepareCallOptions(options: LanguageModelV2CallOptions) {
122
+ const warnings: LanguageModelV2CallWarning[] = [];
123
+
124
+ const zaiOptions = await parseProviderOptions({
125
+ provider: 'zai',
126
+ providerOptions: options.providerOptions,
127
+ schema: zaiLanguageModelChatOptions,
128
+ });
129
+
130
+ if (options.frequencyPenalty != null) {
131
+ warnings.push({
132
+ type: 'unsupported-setting',
133
+ setting: 'frequencyPenalty',
134
+ });
135
+ }
136
+ if (options.presencePenalty != null) {
137
+ warnings.push({
138
+ type: 'unsupported-setting',
139
+ setting: 'presencePenalty',
140
+ });
141
+ }
142
+ if (options.seed != null) {
143
+ warnings.push({ type: 'unsupported-setting', setting: 'seed' });
144
+ }
145
+
146
+ let tools = options.tools;
147
+ let toolChoice = options.toolChoice;
148
+
149
+ if (toolChoice?.type === 'none') {
150
+ tools = undefined;
151
+ toolChoice = undefined;
152
+ } else if (toolChoice != null && toolChoice.type !== 'auto') {
153
+ warnings.push({
154
+ type: 'unsupported-setting',
155
+ setting: 'toolChoice',
156
+ details: 'Z.AI currently supports only automatic tool selection.',
157
+ });
158
+ toolChoice = undefined;
159
+ }
160
+
161
+ const normalizedOptions: LanguageModelV2CallOptions = {
162
+ ...options,
163
+ frequencyPenalty: undefined,
164
+ presencePenalty: undefined,
165
+ seed: undefined,
166
+ tools,
167
+ toolChoice,
168
+ providerOptions:
169
+ zaiOptions == null
170
+ ? options.providerOptions
171
+ : {
172
+ ...options.providerOptions,
173
+ zai: zaiOptions,
174
+ },
175
+ };
176
+
177
+ return { normalizedOptions, warnings };
178
+ }
179
+
180
+ async doGenerate(
181
+ options: Parameters<LanguageModelV2['doGenerate']>[0],
182
+ ): Promise<Awaited<ReturnType<LanguageModelV2['doGenerate']>>> {
183
+ const { normalizedOptions, warnings } =
184
+ await this.prepareCallOptions(options);
185
+ const result = await super.doGenerate(normalizedOptions);
186
+
187
+ return {
188
+ ...result,
189
+ finishReason: mapZaiFinishReason(
190
+ result.finishReason,
191
+ getRawFinishReason(result.response?.body),
192
+ ),
193
+ warnings: [...result.warnings, ...warnings],
194
+ };
195
+ }
196
+
197
+ async doStream(
198
+ options: Parameters<LanguageModelV2['doStream']>[0],
199
+ ): Promise<Awaited<ReturnType<LanguageModelV2['doStream']>>> {
200
+ const originalIncludeRawChunks = options.includeRawChunks;
201
+ const { normalizedOptions, warnings } =
202
+ await this.prepareCallOptions(options);
203
+ const result = await super.doStream({
204
+ ...normalizedOptions,
205
+ includeRawChunks: true,
206
+ });
207
+
208
+ let rawFinishReason: string | undefined;
209
+
210
+ return {
211
+ ...result,
212
+ stream: result.stream.pipeThrough(
213
+ new TransformStream<
214
+ LanguageModelV2StreamPart,
215
+ LanguageModelV2StreamPart
216
+ >({
217
+ transform(part, controller) {
218
+ if (part.type === 'stream-start') {
219
+ controller.enqueue({
220
+ ...part,
221
+ warnings: [...part.warnings, ...warnings],
222
+ });
223
+ return;
224
+ }
225
+
226
+ if (part.type === 'raw') {
227
+ rawFinishReason =
228
+ getRawFinishReason(part.rawValue) ?? rawFinishReason;
229
+ if (originalIncludeRawChunks) {
230
+ controller.enqueue(part);
231
+ }
232
+ return;
233
+ }
234
+
235
+ if (part.type === 'finish') {
236
+ controller.enqueue({
237
+ ...part,
238
+ finishReason: mapZaiFinishReason(
239
+ part.finishReason,
240
+ rawFinishReason,
241
+ ),
242
+ });
243
+ return;
244
+ }
245
+
246
+ controller.enqueue(part);
247
+ },
248
+ }),
249
+ ),
250
+ };
251
+ }
252
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Z.AI chat model ids from the official OpenAPI 1.0.0 specification,
3
+ * retrieved from https://docs.z.ai/openapi.json on 2026-08-26.
4
+ */
5
+ export type ZaiChatModelId =
6
+ | 'glm-5.3'
7
+ | 'glm-5.2'
8
+ | 'glm-5.1'
9
+ | 'glm-5-turbo'
10
+ | 'glm-5'
11
+ | 'glm-4.7'
12
+ | 'glm-4.7-flash'
13
+ | 'glm-4.7-flashx'
14
+ | 'glm-4.6'
15
+ | 'glm-4.5'
16
+ | 'glm-4.5-air'
17
+ | 'glm-4.5-x'
18
+ | 'glm-4.5-airx'
19
+ | 'glm-4.5-flash'
20
+ | 'glm-4-32b-0414-128k'
21
+ | 'glm-5.3-flash'
22
+ | 'glm-5v-turbo'
23
+ | 'glm-4.6v'
24
+ | 'glm-4.6v-flash'
25
+ | 'glm-4.6v-flashx'
26
+ | 'glm-4.5v'
27
+ | 'autoglm-phone-multilingual'
28
+ | (string & {});
@@ -0,0 +1,19 @@
1
+ import type { ProviderErrorStructure } from '@ai-sdk/openai-compatible';
2
+ import { z } from 'zod/v4';
3
+
4
+ const zaiErrorDetailsSchema = z.object({
5
+ code: z.union([z.number(), z.string()]).nullish(),
6
+ message: z.string(),
7
+ });
8
+
9
+ const zaiErrorSchema = z.union([
10
+ zaiErrorDetailsSchema,
11
+ z.object({ error: zaiErrorDetailsSchema }),
12
+ ]);
13
+
14
+ export type ZaiErrorData = z.infer<typeof zaiErrorSchema>;
15
+
16
+ export const zaiErrorStructure: ProviderErrorStructure<ZaiErrorData> = {
17
+ errorSchema: zaiErrorSchema,
18
+ errorToMessage: data => ('error' in data ? data.error.message : data.message),
19
+ };
@@ -0,0 +1,103 @@
1
+ import {
2
+ NoSuchModelError,
3
+ type LanguageModelV2,
4
+ type ProviderV2,
5
+ } from '@ai-sdk/provider';
6
+ import {
7
+ loadApiKey,
8
+ withoutTrailingSlash,
9
+ withUserAgentSuffix,
10
+ type FetchFunction,
11
+ } from '@ai-sdk/provider-utils';
12
+ import { VERSION } from './version';
13
+ import { ZaiChatLanguageModel } from './zai-chat-language-model';
14
+ import type { ZaiChatModelId } from './zai-chat-options';
15
+
16
+ export interface ZaiProviderSettings {
17
+ /**
18
+ * Z.AI API key. Defaults to the `ZAI_API_KEY` environment variable.
19
+ */
20
+ apiKey?: string;
21
+
22
+ /**
23
+ * Base URL for API calls. Defaults to
24
+ * `https://api.z.ai/api/paas/v4`.
25
+ */
26
+ baseURL?: string;
27
+
28
+ /**
29
+ * Custom headers to include in requests.
30
+ */
31
+ headers?: Record<string, string>;
32
+
33
+ /**
34
+ * Custom fetch implementation.
35
+ */
36
+ fetch?: FetchFunction;
37
+ }
38
+
39
+ export interface ZaiProvider extends ProviderV2 {
40
+ /**
41
+ * Creates a Z.AI chat model for text generation.
42
+ */
43
+ (modelId: ZaiChatModelId): LanguageModelV2;
44
+
45
+ /**
46
+ * Creates a Z.AI language model.
47
+ */
48
+ languageModel(modelId: ZaiChatModelId): LanguageModelV2;
49
+
50
+ /**
51
+ * Creates a Z.AI chat model.
52
+ */
53
+ chatModel(modelId: ZaiChatModelId): LanguageModelV2;
54
+
55
+ /**
56
+ * Creates a Z.AI chat model.
57
+ */
58
+ chat(modelId: ZaiChatModelId): LanguageModelV2;
59
+ }
60
+
61
+ export function createZai(options: ZaiProviderSettings = {}): ZaiProvider {
62
+ const baseURL =
63
+ withoutTrailingSlash(options.baseURL) ?? 'https://api.z.ai/api/paas/v4';
64
+
65
+ const getHeaders = () =>
66
+ withUserAgentSuffix(
67
+ {
68
+ Authorization: `Bearer ${loadApiKey({
69
+ apiKey: options.apiKey,
70
+ environmentVariableName: 'ZAI_API_KEY',
71
+ description: 'Z.AI API key',
72
+ })}`,
73
+ ...options.headers,
74
+ },
75
+ `ai-sdk/zai/${VERSION}`,
76
+ );
77
+
78
+ const createLanguageModel = (modelId: ZaiChatModelId) =>
79
+ new ZaiChatLanguageModel(modelId, {
80
+ provider: 'zai.chat',
81
+ baseURL,
82
+ headers: getHeaders,
83
+ fetch: options.fetch,
84
+ });
85
+
86
+ const provider = (modelId: ZaiChatModelId) => createLanguageModel(modelId);
87
+
88
+ provider.specificationVersion = 'v2' as const;
89
+ provider.languageModel = createLanguageModel;
90
+ provider.chatModel = createLanguageModel;
91
+ provider.chat = createLanguageModel;
92
+
93
+ provider.textEmbeddingModel = (modelId: string) => {
94
+ throw new NoSuchModelError({ modelId, modelType: 'textEmbeddingModel' });
95
+ };
96
+ provider.imageModel = (modelId: string) => {
97
+ throw new NoSuchModelError({ modelId, modelType: 'imageModel' });
98
+ };
99
+
100
+ return provider;
101
+ }
102
+
103
+ export const zai = createZai();
package/index.js DELETED
@@ -1 +0,0 @@
1
- export {};