@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.
- package/CHANGELOG.md +29 -0
- package/LICENSE +13 -0
- package/README.md +45 -3
- package/dist/index.d.mts +88 -0
- package/dist/index.d.ts +88 -0
- package/dist/index.js +311 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +290 -0
- package/dist/index.mjs.map +1 -0
- package/docs/200-zai.mdx +159 -0
- package/package.json +66 -11
- package/src/index.ts +6 -0
- package/src/version.ts +6 -0
- package/src/zai-chat-language-model-options.ts +45 -0
- package/src/zai-chat-language-model.ts +252 -0
- package/src/zai-chat-options.ts +28 -0
- package/src/zai-error.ts +19 -0
- package/src/zai-provider.ts +103 -0
- package/index.js +0 -1
|
@@ -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 & {});
|
package/src/zai-error.ts
ADDED
|
@@ -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 {};
|