zhipu-ai-provider
Version:
Vercel AI Custom Provider for Services from Zhipu
781 lines (770 loc) • 26.9 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
createZhipu: () => createZhipu,
zhipu: () => zhipu
});
module.exports = __toCommonJS(index_exports);
// src/zhipu-provider.ts
var import_provider_utils5 = require("@ai-sdk/provider-utils");
// src/zhipu-chat-language-model.ts
var import_provider3 = require("@ai-sdk/provider");
var import_provider_utils3 = require("@ai-sdk/provider-utils");
var import_zod2 = require("zod");
// src/convert-to-zhipu-chat-messages.ts
var import_provider = require("@ai-sdk/provider");
var import_provider_utils = require("@ai-sdk/provider-utils");
function convertToZhipuChatMessages(prompt) {
const messages = [];
for (let i = 0; i < prompt.length; i++) {
const { role, content } = prompt[i];
const isLastMessage = i === prompt.length - 1;
switch (role) {
case "system": {
messages.push({ role: "system", content });
break;
}
case "user": {
if (content.length === 1 && content[0].type === "text") {
messages.push({ role: "user", content: content[0].text });
break;
}
if (content.every((part) => part.type === "text")) {
messages.push({
role: "user",
content: content.map((part) => part.text).join("")
});
break;
}
messages.push({
role: "user",
content: content.map((part) => {
var _a;
switch (part.type) {
case "text": {
return { type: "text", text: part.text };
}
case "image": {
return {
type: "image_url",
image_url: {
url: part.image instanceof URL ? part.image.toString() : `data:${(_a = part.mimeType) != null ? _a : "image/jpeg"};base64,${(0, import_provider_utils.convertUint8ArrayToBase64)(part.image)}`
}
};
}
case "file": {
throw new import_provider.UnsupportedFunctionalityError({
functionality: "File content parts in user messages"
});
}
}
})
});
break;
}
case "assistant": {
let text = "";
const toolCalls = [];
for (const part of content) {
switch (part.type) {
case "text": {
text += part.text;
break;
}
case "redacted-reasoning":
case "reasoning": {
break;
}
case "tool-call": {
toolCalls.push({
id: part.toolCallId,
type: "function",
function: {
name: part.toolName,
arguments: JSON.stringify(part.args)
}
});
break;
}
default: {
const _exhaustiveCheck = part;
throw new Error(`Unsupported part: ${_exhaustiveCheck}`);
}
}
}
messages.push({
role: "assistant",
content: text,
prefix: isLastMessage ? true : void 0,
tool_calls: toolCalls.length > 0 ? toolCalls : void 0
});
break;
}
case "tool": {
for (const toolResponse of content) {
messages.push({
role: "tool",
content: JSON.stringify(toolResponse.result),
tool_call_id: toolResponse.toolCallId
});
}
break;
}
default: {
const _exhaustiveCheck = role;
throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
}
}
}
return messages;
}
// src/map-zhipu-finish-reason.ts
function mapZhipuFinishReason(finishReason) {
switch (finishReason) {
case "stop":
return "stop";
case "length":
return "length";
case "tool_calls":
return "tool-calls";
case "sensitive":
return "content-filter";
case "network_error":
return "error";
default:
return "unknown";
}
}
// src/zhipu-error.ts
var import_provider_utils2 = require("@ai-sdk/provider-utils");
var import_zod = require("zod");
var zhipuErrorDataSchema = import_zod.z.object({
error: import_zod.z.object({
message: import_zod.z.string(),
code: import_zod.z.union([import_zod.z.string(), import_zod.z.number()]).nullish()
})
});
var zhipuFailedResponseHandler = (0, import_provider_utils2.createJsonErrorResponseHandler)({
errorSchema: zhipuErrorDataSchema,
errorToMessage: (data) => data.error.message
});
// src/get-response-metadata.ts
function getResponseMetadata({
id,
model,
created
}) {
return {
id: id != null ? id : void 0,
modelId: model != null ? model : void 0,
timestamp: created != null ? new Date(created * 1e3) : void 0
};
}
// src/zhipu-prepare-tools.ts
var import_provider2 = require("@ai-sdk/provider");
function prepareTools(mode) {
var _a;
const tools = ((_a = mode.tools) == null ? void 0 : _a.length) ? mode.tools : void 0;
const toolWarnings = [];
if (tools == null) {
return { tools: void 0, tool_choice: void 0, toolWarnings };
}
const zhipuTools = [];
for (const tool of tools) {
if (tool.type === "provider-defined") {
toolWarnings.push({ type: "unsupported-tool", tool });
} else {
zhipuTools.push({
type: "function",
function: {
name: tool.name,
description: tool.description,
parameters: tool.parameters
}
});
}
}
const toolChoice = mode.toolChoice;
if (toolChoice == null) {
return { tools: zhipuTools, tool_choice: void 0, toolWarnings };
}
const type = toolChoice.type;
switch (type) {
case "none":
return { tools: zhipuTools, tool_choice: void 0, toolWarnings };
case "auto":
case "required":
return { tools: zhipuTools, tool_choice: "auto", toolWarnings };
// zhipu does not support tool mode directly,
// so we filter the tools and force the tool choice through 'any'
case "tool":
return {
tools: zhipuTools.filter(
(tool) => tool.function.name === toolChoice.toolName
),
tool_choice: "auto",
toolWarnings
};
default: {
const _exhaustiveCheck = type;
throw new import_provider2.UnsupportedFunctionalityError({
functionality: `Unsupported tool choice type: ${_exhaustiveCheck}`
});
}
}
}
// src/zhipu-chat-language-model.ts
var ZhipuChatLanguageModel = class {
/**
* Constructs a new ZhipuChatLanguageModel.
* @param modelId - The model identifier.
* @param settings - Settings for the chat.
* @param config - Model configuration.
*/
constructor(modelId, settings, config) {
this.specificationVersion = "v1";
this.defaultObjectGenerationMode = "json";
this.supportsImageUrls = false;
this.modelId = modelId;
this.settings = settings;
this.config = config;
this.config.isMultiModel = this.modelId.includes("4v");
this.config.isReasoningModel = this.modelId.includes("zero");
}
/**
* Getter for the provider name.
*/
get provider() {
return this.config.provider;
}
getArgs({
mode,
prompt,
maxTokens,
temperature,
topP,
topK,
frequencyPenalty,
presencePenalty,
stopSequences,
responseFormat,
seed
}) {
const type = mode.type;
const warnings = [];
if (!this.config.isMultiModel && prompt.every((msg) => msg.role === "user" && !msg.content.every((part) => part.type === "text"))) {
warnings.push({
type: "other",
message: "Non-vision models does not support message parts"
});
}
if (topK != null) {
warnings.push({
type: "unsupported-setting",
setting: "topK"
});
}
if (frequencyPenalty != null) {
warnings.push({
type: "unsupported-setting",
setting: "frequencyPenalty"
});
}
if (presencePenalty != null) {
warnings.push({
type: "unsupported-setting",
setting: "presencePenalty"
});
}
if (stopSequences != null && this.config.isMultiModel) {
warnings.push({
type: "unsupported-setting",
setting: "stopSequences",
details: "Stop sequences are not supported for vision model"
});
}
if (stopSequences != null && stopSequences.length > 1) {
warnings.push({
type: "unsupported-setting",
setting: "stopSequences",
details: "Only supports one stop sequence"
});
}
if (seed != null) {
warnings.push({
type: "unsupported-setting",
setting: "seed"
});
}
if (responseFormat != null && responseFormat.type === "json" && (this.config.isMultiModel || this.config.isReasoningModel)) {
warnings.push({
type: "unsupported-setting",
setting: "responseFormat",
details: "JSON response format is not supported with vision and reasoning models."
});
}
if (responseFormat != null && responseFormat.type === "json" && responseFormat.schema != null) {
warnings.push({
type: "unsupported-setting",
setting: "responseFormat",
details: "JSON response format schema is only supported with structuredOutputs, provide the schema."
});
}
const baseArgs = {
// model id:
model: this.modelId,
// model specific settings:
user_id: this.settings.userId,
do_sample: this.settings.doSample,
request_id: this.settings.requestId,
// standardized settings:
max_tokens: maxTokens,
temperature,
top_p: topP,
// response format:
response_format: (responseFormat == null ? void 0 : responseFormat.type) === "json" ? { type: "json_object" } : void 0,
// messages:
messages: convertToZhipuChatMessages(prompt)
};
switch (type) {
case "regular": {
const { tools, tool_choice, toolWarnings } = prepareTools(mode);
return {
args: { ...baseArgs, tools, tool_choice },
warnings: [...warnings, ...toolWarnings]
};
}
case "object-json": {
return {
args: {
...baseArgs,
response_format: { type: "json_object" }
},
warnings
};
}
case "object-tool": {
return {
args: {
...baseArgs,
tool_choice: "auto",
tools: [mode.tool]
},
warnings
};
}
default: {
const _exhaustiveCheck = type;
throw new Error(`Unsupported type: ${_exhaustiveCheck}`);
}
}
}
async doGenerate(options) {
var _a, _b, _c;
const { args, warnings } = this.getArgs(options);
const { responseHeaders, value: response } = await (0, import_provider_utils3.postJsonToApi)({
url: `${this.config.baseURL}/chat/completions`,
headers: (0, import_provider_utils3.combineHeaders)(this.config.headers(), options.headers),
body: args,
failedResponseHandler: zhipuFailedResponseHandler,
successfulResponseHandler: (0, import_provider_utils3.createJsonResponseHandler)(
zhipuChatResponseSchema
),
abortSignal: options.abortSignal,
fetch: this.config.fetch
});
const { messages: rawPrompt, ...rawSettings } = args;
const choice = response.choices[0];
return {
text: (_a = choice.message.content) != null ? _a : void 0,
toolCalls: (_b = choice.message.tool_calls) == null ? void 0 : _b.map((toolCall) => ({
toolCallType: "function",
toolCallId: toolCall.id,
toolName: toolCall.function.name,
args: toolCall.function.arguments
})),
finishReason: mapZhipuFinishReason(choice.finish_reason),
usage: {
promptTokens: response.usage.prompt_tokens,
completionTokens: (_c = response.usage.completion_tokens) != null ? _c : NaN
},
rawCall: { rawPrompt, rawSettings },
rawResponse: { headers: responseHeaders },
request: { body: JSON.stringify(args) },
response: getResponseMetadata(response),
warnings
};
}
async doStream(options) {
const { args, warnings } = this.getArgs(options);
const body = { ...args, stream: true };
const { responseHeaders, value: response } = await (0, import_provider_utils3.postJsonToApi)({
url: `${this.config.baseURL}/chat/completions`,
headers: (0, import_provider_utils3.combineHeaders)(this.config.headers(), options.headers),
body,
failedResponseHandler: zhipuFailedResponseHandler,
successfulResponseHandler: (0, import_provider_utils3.createEventSourceResponseHandler)(zhipuChatChunkSchema),
abortSignal: options.abortSignal,
fetch: this.config.fetch
});
const { messages: rawPrompt, ...rawSettings } = args;
const toolCalls = [];
let finishReason = "unknown";
let usage = {
promptTokens: void 0,
completionTokens: void 0
};
let isFirstChunk = true;
return {
stream: response.pipeThrough(
new TransformStream({
transform(chunk, controller) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
if (chunk.success == false) {
finishReason = "error";
controller.enqueue({ type: "error", error: chunk.error });
return;
}
const value = chunk.value;
if (isFirstChunk) {
isFirstChunk = false;
controller.enqueue({
type: "response-metadata",
...getResponseMetadata(value)
});
}
if (value.usage != null) {
const { prompt_tokens, completion_tokens } = value.usage;
usage = {
promptTokens: prompt_tokens != null ? prompt_tokens : void 0,
completionTokens: completion_tokens != null ? completion_tokens : void 0
};
}
const choice = value.choices[0];
if ((choice == null ? void 0 : choice.finish_reason) != null) {
if (choice.finish_reason === "network_error") {
controller.enqueue({
type: "error",
error: new Error(`Error: Network Error`)
});
return;
}
finishReason = mapZhipuFinishReason(choice.finish_reason);
}
if ((choice == null ? void 0 : choice.delta) == null) {
return;
}
const delta = choice.delta;
if (delta.content != null) {
controller.enqueue({
type: "text-delta",
textDelta: delta.content
});
}
const mappedToolCalls = delta.tool_calls;
if (mappedToolCalls != null) {
for (const toolCallDelta of mappedToolCalls) {
const index = toolCallDelta.index;
if (toolCalls[index] == null) {
if (toolCallDelta.type !== "function") {
throw new import_provider3.InvalidResponseDataError({
data: toolCallDelta,
message: `Expected 'function' type.`
});
}
if (toolCallDelta.id == null) {
throw new import_provider3.InvalidResponseDataError({
data: toolCallDelta,
message: `Expected 'id' to be a string.`
});
}
if (((_a = toolCallDelta.function) == null ? void 0 : _a.name) == null) {
throw new import_provider3.InvalidResponseDataError({
data: toolCallDelta,
message: `Expected 'function.name' to be a string.`
});
}
toolCalls[index] = {
id: toolCallDelta.id,
type: "function",
function: {
name: toolCallDelta.function.name,
arguments: (_b = toolCallDelta.function.arguments) != null ? _b : ""
},
hasFinished: false
};
const toolCall2 = toolCalls[index];
if (((_c = toolCall2.function) == null ? void 0 : _c.name) != null && ((_d = toolCall2.function) == null ? void 0 : _d.arguments) != null) {
if (toolCall2.function.arguments.length > 0) {
controller.enqueue({
type: "tool-call-delta",
toolCallType: "function",
toolCallId: toolCall2.id,
toolName: toolCall2.function.name,
argsTextDelta: toolCall2.function.arguments
});
}
if ((0, import_provider_utils3.isParsableJson)(toolCall2.function.arguments)) {
controller.enqueue({
type: "tool-call",
toolCallType: "function",
toolCallId: (_e = toolCall2.id) != null ? _e : (0, import_provider_utils3.generateId)(),
toolName: toolCall2.function.name,
args: toolCall2.function.arguments
});
toolCall2.hasFinished = true;
}
}
continue;
}
const toolCall = toolCalls[index];
if (toolCall.hasFinished) {
continue;
}
if (((_f = toolCallDelta.function) == null ? void 0 : _f.arguments) != null) {
toolCall.function.arguments += (_h = (_g = toolCallDelta.function) == null ? void 0 : _g.arguments) != null ? _h : "";
}
controller.enqueue({
type: "tool-call-delta",
toolCallType: "function",
toolCallId: toolCall.id,
toolName: toolCall.function.name,
argsTextDelta: (_i = toolCallDelta.function.arguments) != null ? _i : ""
});
if (((_j = toolCall.function) == null ? void 0 : _j.name) != null && ((_k = toolCall.function) == null ? void 0 : _k.arguments) != null && (0, import_provider_utils3.isParsableJson)(toolCall.function.arguments)) {
controller.enqueue({
type: "tool-call",
toolCallType: "function",
toolCallId: (_l = toolCall.id) != null ? _l : (0, import_provider_utils3.generateId)(),
toolName: toolCall.function.name,
args: toolCall.function.arguments
});
toolCall.hasFinished = true;
}
}
}
},
flush(controller) {
var _a, _b;
controller.enqueue({
type: "finish",
finishReason,
usage: {
promptTokens: (_a = usage.promptTokens) != null ? _a : NaN,
completionTokens: (_b = usage.completionTokens) != null ? _b : NaN
}
});
}
})
),
rawCall: { rawPrompt, rawSettings },
rawResponse: { headers: responseHeaders },
request: { body: JSON.stringify(body) },
warnings
};
}
};
var zhipuChatResponseSchema = import_zod2.z.object({
id: import_zod2.z.string().nullish(),
created: import_zod2.z.number().nullish(),
model: import_zod2.z.string().nullish(),
choices: import_zod2.z.array(
import_zod2.z.object({
message: import_zod2.z.object({
role: import_zod2.z.literal("assistant"),
content: import_zod2.z.string().nullish(),
tool_calls: import_zod2.z.array(
import_zod2.z.object({
id: import_zod2.z.string(),
index: import_zod2.z.number().nullish(),
type: import_zod2.z.literal("function"),
function: import_zod2.z.object({ name: import_zod2.z.string(), arguments: import_zod2.z.string() })
})
).nullish()
}),
index: import_zod2.z.number(),
finish_reason: import_zod2.z.string().nullish()
})
),
usage: import_zod2.z.object({
prompt_tokens: import_zod2.z.number(),
completion_tokens: import_zod2.z.number().nullish(),
total_tokens: import_zod2.z.number().nullish()
}),
web_search: import_zod2.z.object({
icon: import_zod2.z.string(),
title: import_zod2.z.string(),
link: import_zod2.z.string(),
media: import_zod2.z.string(),
content: import_zod2.z.string()
}).nullish()
});
var zhipuChatChunkSchema = import_zod2.z.object({
id: import_zod2.z.string().nullish(),
created: import_zod2.z.number().nullish(),
model: import_zod2.z.string().nullish(),
choices: import_zod2.z.array(
import_zod2.z.object({
delta: import_zod2.z.object({
role: import_zod2.z.enum(["assistant"]).optional(),
content: import_zod2.z.string().nullish(),
tool_calls: import_zod2.z.array(
import_zod2.z.object({
id: import_zod2.z.string(),
index: import_zod2.z.number(),
type: import_zod2.z.literal("function"),
function: import_zod2.z.object({ name: import_zod2.z.string(), arguments: import_zod2.z.string() })
})
).nullish()
}),
finish_reason: import_zod2.z.string().nullish(),
index: import_zod2.z.number()
})
),
usage: import_zod2.z.object({
prompt_tokens: import_zod2.z.number(),
completion_tokens: import_zod2.z.number().nullish(),
total_tokens: import_zod2.z.number().nullish()
}).nullish(),
web_search: import_zod2.z.object({
icon: import_zod2.z.string(),
title: import_zod2.z.string(),
link: import_zod2.z.string(),
media: import_zod2.z.string(),
content: import_zod2.z.string()
}).nullish()
});
// src/zhipu-embedding-model.ts
var import_provider4 = require("@ai-sdk/provider");
var import_provider_utils4 = require("@ai-sdk/provider-utils");
var import_zod3 = require("zod");
var ZhipuEmbeddingModel = class {
constructor(modelId, settings, config) {
this.specificationVersion = "v1";
this.modelId = modelId;
this.settings = settings;
this.config = config;
}
get provider() {
return this.config.provider;
}
get maxEmbeddingsPerCall() {
var _a;
return (_a = this.config.maxEmbeddingsPerCall) != null ? _a : 64;
}
get supportsParallelCalls() {
var _a;
return (_a = this.config.supportsParallelCalls) != null ? _a : true;
}
async doEmbed({
values,
abortSignal,
headers
}) {
if (values.length > this.maxEmbeddingsPerCall) {
throw new import_provider4.TooManyEmbeddingValuesForCallError({
provider: this.provider,
modelId: this.modelId,
maxEmbeddingsPerCall: this.maxEmbeddingsPerCall,
values
});
}
const { responseHeaders, value: response } = await (0, import_provider_utils4.postJsonToApi)({
url: `${this.config.baseURL}/embeddings`,
headers: (0, import_provider_utils4.combineHeaders)(this.config.headers(), headers),
body: {
model: this.modelId,
input: values,
dimension: this.settings.dimensions
},
failedResponseHandler: zhipuFailedResponseHandler,
successfulResponseHandler: (0, import_provider_utils4.createJsonResponseHandler)(
ZhipuTextEmbeddingResponseSchema
),
abortSignal,
fetch: this.config.fetch
});
return {
embeddings: response.data.map((item) => item.embedding),
usage: response.usage ? { tokens: response.usage.prompt_tokens } : void 0,
rawResponse: { headers: responseHeaders }
};
}
};
var ZhipuTextEmbeddingResponseSchema = import_zod3.z.object({
data: import_zod3.z.array(
import_zod3.z.object({
embedding: import_zod3.z.array(import_zod3.z.number()),
index: import_zod3.z.number().nullish(),
object: import_zod3.z.string().nullish()
})
),
usage: import_zod3.z.object({
prompt_tokens: import_zod3.z.number(),
total_tokens: import_zod3.z.number().nullish()
}).nullish()
});
// src/zhipu-provider.ts
function createZhipu(options = {}) {
var _a;
const baseURL = (_a = (0, import_provider_utils5.withoutTrailingSlash)(options.baseURL)) != null ? _a : "https://open.bigmodel.cn/api/paas/v4";
const getHeaders = () => ({
Authorization: `Bearer ${(0, import_provider_utils5.loadApiKey)({
apiKey: options.apiKey,
environmentVariableName: "ZHIPU_API_KEY",
description: "ZHIPU API key"
})}`,
...options.headers
});
const createChatModel = (modelId, settings = {}) => new ZhipuChatLanguageModel(modelId, settings, {
provider: "zhipu.chat",
baseURL,
headers: getHeaders,
fetch: options.fetch
});
const createEmbeddingModel = (modelId, settings = {}) => new ZhipuEmbeddingModel(modelId, settings, {
provider: "zhipu.embedding",
baseURL,
headers: getHeaders,
fetch: options.fetch
});
const provider = function(modelId, settings) {
if (new.target) {
throw new Error(
"The Zhipu model function cannot be called with the new keyword."
);
}
return createChatModel(modelId, settings);
};
provider.languageModel = createChatModel;
provider.chat = createChatModel;
provider.embedding = createEmbeddingModel;
provider.textEmbedding = createEmbeddingModel;
provider.textEmbeddingModel = createEmbeddingModel;
return provider;
}
var zhipu = createZhipu();
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
createZhipu,
zhipu
});
//# sourceMappingURL=index.js.map