chaite
Version:
core for chatgpt-plugin and karin-plugin-chatgpt
1,882 lines (1,850 loc) • 284 kB
JavaScript
import { s as __toESM } from "./rolldown-runtime-DVriDoez.mjs";
import { t as __dirname } from "./__dirname-BYuaqN8u.mjs";
import "./chunks/lop/index.mjs-BWbOMJZv.mjs";
import "./chunks/bluebird/index.mjs-D4zFjek8.mjs";
import { t as require_lib } from "./chunks/mammoth/index.mjs-DOMhYI-I.mjs";
import { n as GoogleGenAI, r as Type, t as FunctionCallingConfigMode } from "./chunks/@google/genai/index.mjs-BrdPnzXZ.mjs";
import "./chunks/jszip/index.mjs-DKtD_vT2.mjs";
import "./chunks/isarray/index.mjs-DaT02uUW.mjs";
import "./chunks/core-util-is/index.mjs-C0h_2dGX.mjs";
import "./chunks/body-parser/index.mjs-Bj6nfRGh.mjs";
import "./chunks/immediate/index.mjs-CkWjI_b-.mjs";
import "./chunks/@xmldom/xmldom/index.mjs-BARr5-gb.mjs";
import "./chunks/dingbat-to-unicode/index.mjs-DjR5pQCM.mjs";
import { t as axios_default } from "./chunks/axios/index.mjs-BJujW20l.mjs";
import "./chunks/accepts/index.mjs-CtXuJELB.mjs";
import "./chunks/asynckit/index.mjs-DShOwGhP.mjs";
import { t as sdk_default } from "./chunks/@anthropic-ai/sdk/index.mjs-sKjldQtK.mjs";
import { t as require_jsonwebtoken } from "./chunks/jsonwebtoken/index.mjs-DOuYe9_G.mjs";
import { t as src_default } from "./chunks/@karinjs/node-schedule/index.mjs-Ciyd8XlD.mjs";
import { t as esm_default } from "./chunks/chokidar/index.mjs-Dc80JdeQ.mjs";
import { t as OpenAI } from "./chunks/openai/index.mjs-CaEygjxO.mjs";
import { t as require_express } from "./chunks/express/index.mjs-DFJbf4Rc.mjs";
import "./chunks/encodeurl/index.mjs-BI1DQR59.mjs";
import "./chunks/escape-html/index.mjs-CH24eAfR.mjs";
import "./chunks/array-flatten/index.mjs-CQr55PjM.mjs";
import "./chunks/content-disposition/index.mjs-d-2yLiD4.mjs";
import "./chunks/etag/index.mjs-wzo82OOp.mjs";
import "./chunks/cookie-signature/index.mjs-BMcPfKwp.mjs";
import "./chunks/cookie/index.mjs-HM-UN05t.mjs";
import { t as require_lib$1 } from "./chunks/cors/index.mjs-DqcZUs8E.mjs";
import { t as McpToolExecutor } from "./mcp-DnSId7pp.mjs";
import * as path$2 from "node:path";
import { AsyncLocalStorage } from "async_hooks";
import fs from "fs/promises";
import path$1 from "path";
import * as fs$1 from "node:fs";
import { promises as promises$1 } from "fs";
import EventEmitter from "node:events";
import * as crypto from "node:crypto";
import { spawn } from "node:child_process";
//#region src/types/cloud.ts
var AbstractShareable = class {
constructor(params) {
if (params) {
if (params.id) this.id = params.id;
if (params.name) this.name = params.name;
if (params.embedded) this.embedded = params.embedded;
if (params.uploader) this.uploader = params.uploader;
if (params.createdAt) this.createdAt = params.createdAt;
if (params.updatedAt) this.updatedAt = params.updatedAt;
if (params.cloudId) this.cloudId = params.cloudId;
if (params.description) this.description = params.description;
if (params.modelType) this.modelType = params.modelType;
if (params.code) this.code = params.code;
if (params.md5) this.md5 = params.md5;
}
}
modelType;
code;
createdAt;
description;
embedded;
id;
cloudId;
name;
uploader;
updatedAt;
fromString(str) {
return JSON.parse(str);
}
toString() {
return JSON.stringify(this);
}
toFormatedString(verbose) {
return JSON.stringify(this, null, 2);
}
md5;
};
//#endregion
//#region src/types/common.ts
const MultipleKeyStrategyChoice = {
RANDOM: "random",
ROUND_ROBIN: "round-robin",
CONVERSATION_HASH: "conversation-hash"
};
var BaseClientOptions = class BaseClientOptions {
features;
tools;
baseUrl;
apiKey;
multipleKeyStrategy;
proxy;
historyManager;
logger;
postProcessorIds;
postProcessors;
preProcessorIds;
preProcessors;
/**
* Optional ToolExecutor for remote-first / sandbox tool execution.
* If provided, AbstractClient will use it instead of calling tool.run() directly.
*/
toolExecutor;
/** Per-tool call timeout in ms (used by ToolExecutor if supported) */
toolTimeoutMs;
constructor(options) {
if (options) {
this.features = options.features || [];
this.tools = options.tools || [];
this.baseUrl = options.baseUrl || "";
this.apiKey = options.apiKey || "";
this.multipleKeyStrategy = options.multipleKeyStrategy;
this.proxy = options.proxy;
this.preProcessorIds = options.preProcessorIds;
this.postProcessorIds = options.postProcessorIds;
if (options.historyManager) this.historyManager = options.historyManager;
this.logger = options.logger;
this.toolExecutor = options.toolExecutor;
this.toolTimeoutMs = options.toolTimeoutMs;
this.init();
}
}
static create(options) {
return options instanceof BaseClientOptions ? options : new BaseClientOptions(options);
}
initPromise;
async ready() {
return this.initPromise;
}
setHistoryManager(historyManager) {
this.historyManager = historyManager;
}
setLogger(logger) {
this.logger = logger;
}
getPostProcessors() {
return this.postProcessors || [];
}
getPreProcessors() {
return this.preProcessors || [];
}
async init() {
this.initPromise = (async () => {})();
}
toString() {
const json = {
features: this.features,
tools: this.tools,
baseUrl: this.baseUrl,
apiKey: this.apiKey,
multipleKeyStrategy: this.multipleKeyStrategy,
proxy: this.proxy,
postProcessors: this.postProcessors?.map((p) => p.id),
preProcessors: this.preProcessors?.map((p) => p.id)
};
return JSON.stringify(json);
}
fromString(str) {
return new BaseClientOptions(JSON.parse(str));
}
};
const DefaultLogger = new class DefaultLogger$1 {
name;
enableColors;
static COLORS = {
reset: "\x1B[0m",
debug: "\x1B[36m",
info: "\x1B[32m",
warn: "\x1B[33m",
error: "\x1B[31m"
};
constructor(name = "Chaite", enableColors = true) {
this.name = name;
this.enableColors = enableColors;
}
formatDate() {
const now = /* @__PURE__ */ new Date();
return `${now.getHours().toString().padStart(2, "0")}:${now.getMinutes().toString().padStart(2, "0")}:${now.getSeconds().toString().padStart(2, "0")}.${now.getMilliseconds().toString().padStart(3, "0")}`;
}
formatMessage(level, msg, args) {
const prefix = `[${this.name}][${this.formatDate()}][${level}]`;
const formattedMsg = typeof msg === "string" ? msg : JSON.stringify(msg, null, 2);
if (this.enableColors) return `${DefaultLogger$1.COLORS[level.toLowerCase()] || ""}${prefix}${DefaultLogger$1.COLORS.reset} ${formattedMsg}`;
return `${prefix} ${formattedMsg}`;
}
debug(msg, ...args) {
console.log(this.formatMessage("DEBUG", msg, args), ...args);
}
error(msg, ...args) {
console.log(this.formatMessage("ERROR", msg, args), ...args);
}
info(msg, ...args) {
console.log(this.formatMessage("INFO", msg, args), ...args);
}
warn(msg, ...args) {
console.log(this.formatMessage("WARN", msg, args), ...args);
}
}();
var ChaiteContext = class {
constructor(logger) {
this.logger = logger;
}
logger;
chaite;
options;
historyMessages;
event;
data;
client;
/** Set when this context is running inside a background job */
jobId;
/** Set when this context is executing a plan */
planId;
/** Active skill name for this request */
skillName;
/** Active workflow id for this request */
workflowId;
/** Resource identity used by usage logging. */
channelId;
channelName;
presetId;
presetName;
setHistoryMessages(histories) {
this.historyMessages = histories;
}
getHistoryMessages() {
return this.historyMessages;
}
setOptions(options) {
this.options = options;
}
getOptions() {
return this.options;
}
setEvent(event) {
this.event = event;
}
setChaite(chaite) {
this.chaite = chaite;
}
getEvent() {
return this.event;
}
setData(data) {
this.data = data;
}
getData() {
return this.data;
}
setClient(client) {
this.client = client;
}
getClient() {
return this.client;
}
getChaite() {
return this.chaite;
}
};
//#endregion
//#region src/types/tools.ts
var ToolDTO = class ToolDTO extends AbstractShareable {
constructor(params) {
super(params);
this.modelType = "executable";
this.permission = params.permission || "private";
this.status = params.status || "enabled";
}
status;
permission;
toFormatedString(_verbose) {
let base = `ID: ${this.id}\n工具名称:${this.name}`;
if (this.description) base += `\n工具描述:${this.description}`;
if (this.permission) base += `\n权限:${this.permission}`;
if (this.createdAt) base += `\n创建时间:${this.createdAt}`;
if (this.updatedAt) base += `\n最后更新时间:${this.updatedAt}`;
if (this.uploader?.username) base += `\n上传者:@${this.uploader.username}`;
return base.trimEnd();
}
fromString(str) {
return new ToolDTO(JSON.parse(str));
}
};
var ToolsGroupDTO = class extends AbstractShareable {
constructor(params) {
super(params);
this.modelType = "settings";
}
toolIds;
isDefault;
toFormatedString(_verbose) {
let base = `工具组名称:${this.name}`;
if (this.description) base += `\n工具组描述:${this.description}`;
if (this.createdAt) base += `\n创建时间:${this.createdAt}`;
if (this.updatedAt) base += `\n最后更新时间:${this.updatedAt}`;
if (this.uploader?.username) base += `\n上传者:@${this.uploader.username}`;
return base.trimEnd();
}
};
/**
* js写的工具可以继承这个抽象类
*/
var CustomTool = class {
constructor() {
if (!this.name) this.name = this.function.name;
}
type = "function";
function = {
name: "",
description: "",
parameters: {
type: "object",
properties: {},
required: []
}
};
async run(_args, _context = new ChaiteContext()) {
throw new Error("Not implemented");
}
name;
};
//#endregion
//#region src/types/document.ts
var DocumentPathParser = class {
isCompatibleType(value) {
return typeof value === "string";
}
supportedExtensions;
type;
parse(document) {
throw new Error("abstract class");
}
};
var DocumentFileParser = class {
isCompatibleType(value) {
return Buffer.isBuffer(value);
}
supportedExtensions;
type;
parse(document) {
throw new Error("abstract class");
}
};
//#endregion
//#region src/types/channel.ts
var ChannelStatistics = class {
callTimes;
useToken;
perModel;
fromString(str) {
const channel = JSON.parse(str);
this.callTimes = channel.callTimes;
this.useToken = channel.useToken;
this.perModel = channel.perModel;
return this;
}
toString() {
return JSON.stringify(this);
}
};
//#endregion
//#region src/types/adapter.ts
var SendMessageOption = class SendMessageOption {
constructor(option) {
this.model = option.model;
this.temperature = option.temperature;
this.maxToken = option.maxToken;
this.systemOverride = option.systemOverride;
this.disableHistoryRead = option.disableHistoryRead;
this.disableHistorySave = option.disableHistorySave;
this.conversationId = option.conversationId;
this.parentMessageId = option.parentMessageId;
this.stream = option.stream;
this.isThinkingModel = option.isThinkingModel;
this.enableReasoning = option.enableReasoning;
this.reasoningEffort = option.reasoningEffort;
this.reasoningBudgetTokens = option.reasoningBudgetTokens;
this.toolChoice = option.toolChoice;
this.preProcessorIds = option.preProcessorIds;
this.postProcessorIds = option.postProcessorIds;
this.toolGroupId = option.toolGroupId;
this.safetySettings = option.safetySettings;
this.responseModalities = option.responseModalities;
this.onChunk = option.onChunk;
this.onMessageWithToolCall = option.onMessageWithToolCall;
this.toolCallLimit = option.toolCallLimit;
this._consecutiveToolCallCount = option._consecutiveToolCallCount;
this._consecutiveIdenticalToolCallCount = option._consecutiveIdenticalToolCallCount;
this._lastToolCallSignature = option._lastToolCallSignature;
this.toolTimeoutMs = option.toolTimeoutMs;
this.jobId = option.jobId;
this.planId = option.planId;
this.skillName = option.skillName;
}
static create(options) {
return options instanceof SendMessageOption ? options : new SendMessageOption(options || {});
}
model;
temperature;
maxToken;
/**
* 将系统提示词覆盖
*/
systemOverride;
/**
* 本轮对话禁用历史
*/
disableHistoryRead;
/**
* 禁用本轮对话存储到历史
*/
disableHistorySave;
/**
* 对话ID。如果不传则默认为第一次对话
*/
conversationId;
/**
* 上一条消息的ID,如果不传则默认为第一次对话
*/
parentMessageId;
/**
* 流模式
*/
stream;
/**
* 是否是思考模型
*/
isThinkingModel;
enableReasoning;
reasoningEffort;
reasoningBudgetTokens;
toolChoice;
postProcessorIds;
preProcessorIds;
toolGroupId;
responseModalities;
safetySettings;
toolCallLimit;
_consecutiveToolCallCount;
_consecutiveIdenticalToolCallCount;
_lastToolCallSignature;
/**
* Per-tool call timeout in ms. Overrides channel-level toolTimeoutMs.
*/
toolTimeoutMs;
/**
* Agent context fields propagated through the call chain.
* Set automatically by Chaite when running under a background job or plan.
*/
jobId;
planId;
skillName;
fromString(str) {
return JSON.parse(str);
}
toString() {
const json = {
model: this.model,
temperature: this.temperature,
maxToken: this.maxToken,
systemOverride: this.systemOverride,
disableHistoryRead: this.disableHistoryRead,
disableHistorySave: this.disableHistorySave,
conversationId: this.conversationId,
parentMessageId: this.parentMessageId,
stream: this.stream,
isThinkingModel: this.isThinkingModel,
enableReasoning: this.enableReasoning,
reasoningEffort: this.reasoningEffort,
reasoningBudgetTokens: this.reasoningBudgetTokens,
toolChoice: this.toolChoice,
preProcessorIds: this.preProcessorIds,
postProcessorIds: this.postProcessorIds,
toolGroupId: this.toolGroupId,
responseModalities: this.responseModalities,
safetySettings: this.safetySettings,
toolCallLimit: this.toolCallLimit
};
return JSON.stringify(json);
}
};
var AbstractHistoryManager = class {
name;
};
//#endregion
//#region src/const/cloud_api.ts
const API_V1_PREFIX = "/api/v2";
const CloudAPI = {
USER: API_V1_PREFIX + "/user",
LIST: {
tool: API_V1_PREFIX + "/tools",
processor: API_V1_PREFIX + "/processors",
channel: API_V1_PREFIX + "/channels",
"chat-preset": API_V1_PREFIX + "/presets",
"tool-group": API_V1_PREFIX + "/toolGroups",
"trigger": API_V1_PREFIX + "/triggers"
},
ADD: {
tool: API_V1_PREFIX + "/tool",
processor: API_V1_PREFIX + "/processor",
channel: API_V1_PREFIX + "/channel",
"chat-preset": API_V1_PREFIX + "/preset",
"tool-group": API_V1_PREFIX + "/toolGroups",
"trigger": API_V1_PREFIX + "/trigger"
},
GET: {
tool: API_V1_PREFIX + "/tool/",
processor: API_V1_PREFIX + "/processor/",
channel: API_V1_PREFIX + "/channel/",
"chat-preset": API_V1_PREFIX + "/preset/",
"tool-group": API_V1_PREFIX + "/toolGroups/",
"trigger": API_V1_PREFIX + "/trigger/"
},
TEMP_SHARE: {
tool: API_V1_PREFIX + "/tool",
processor: API_V1_PREFIX + "/processor",
channel: API_V1_PREFIX + "/channel",
"chat-preset": API_V1_PREFIX + "/preset",
"tool-group": API_V1_PREFIX + "/toolGroups",
"trigger": API_V1_PREFIX + "/trigger"
},
DELETE: {
tool: API_V1_PREFIX + "/tool",
processor: API_V1_PREFIX + "/processor",
channel: API_V1_PREFIX + "/channel",
"chat-preset": API_V1_PREFIX + "/preset",
"tool-group": API_V1_PREFIX + "/toolGroups",
"trigger": API_V1_PREFIX + "/trigger"
}
};
//#endregion
//#region src/const/map.ts
const CHANNEL_STATUS_MAP = {
enabled: "启用",
disabled: "禁用"
};
const PROCESSOR_TYPE_MAP = {
pre: "前置处理器",
post: "后置处理器"
};
//#endregion
//#region src/types/processors.ts
var ProcessorDTO = class ProcessorDTO extends AbstractShareable {
constructor(params) {
super(params);
this.modelType = "executable";
if (params.type) this.type = params.type;
}
type;
fromString(str) {
return new ProcessorDTO(JSON.parse(str));
}
toFormatedString(_verbose) {
let base = `处理器ID:${this.id}`;
if (this.name) base += `\n处理器名称:${this.name}`;
if (this.type) base += `\n类型:${PROCESSOR_TYPE_MAP[this.type]}`;
if (this.description) base += `\n描述:${this.description}`;
if (this.createdAt) base += `\n创建时间:${this.createdAt}`;
if (this.updatedAt) base += `\n最后更新时间:${this.updatedAt}`;
if (this.uploader?.username) base += `\n上传者:@${this.uploader.username}`;
return base.trimEnd();
}
};
/**
* 继承这个来实现一个前处理器
*/
var PreProcessor = class {
type;
name;
id;
};
/**
* 继承这个来实现一个后处理器
*/
var PostProcessor = class {
type;
name;
id;
};
//#endregion
//#region src/types/storage.ts
var ChaiteStorage = class {
getName() {
return "unknown";
}
};
//#endregion
//#region src/types/server.ts
var ChaiteResponse = class ChaiteResponse {
constructor(code, data, message) {
this.code = code;
this.data = data;
this.message = message;
}
static ok(data) {
return new ChaiteResponse(0, data, "ok");
}
static okm(data, msg) {
return new ChaiteResponse(0, data, msg);
}
static fail(data, msg) {
return new ChaiteResponse(-1, data, msg);
}
static failc(data, msg, code) {
return new ChaiteResponse(code, data, msg);
}
};
//#endregion
//#region src/types/external.ts
var AbstractUserModeSelector = class {};
//#endregion
//#region src/utils/helpers.ts
async function getKey(apiKeys, strategy) {
const logger = asyncLocalStorage.getStore()?.logger;
const candidateApiKeys = Array.isArray(apiKeys) ? apiKeys : [apiKeys];
const keyNum = candidateApiKeys.length;
if (keyNum === 0) {
logger.error(`No key ${keyNum} found.`);
throw new Error("No key provided");
}
let apiKey;
switch (strategy) {
case MultipleKeyStrategyChoice.RANDOM:
apiKey = candidateApiKeys[Math.floor(Math.random() * keyNum)];
break;
case MultipleKeyStrategyChoice.ROUND_ROBIN:
logger.warn("ROUND_ROBIN is not supported yet");
throw new Error("ROUND_ROBIN is not supported yet");
case MultipleKeyStrategyChoice.CONVERSATION_HASH:
logger.warn("CONVERSATION_HASH is not supported yet");
throw new Error("CONVERSATION_HASH is not supported yet");
default: throw new Error("unknown MultipleKeyStrategy");
}
return apiKey;
}
const asyncLocalStorage = new AsyncLocalStorage();
async function useEvent() {
return asyncLocalStorage.getStore()?.getEvent();
}
/**
* 将JS代码保存到指定目录并导入其默认导出
*
* @param {string} jsContent - JS代码内容
* @param {string} modulesDir - 保存模块的目录
* @param {string} fileName - 文件名(不含路径)
* @param {Function} AbstractClass - 抽象类,用于检查实例是否继承自它
* @returns {Promise<T | null>} 如果默认导出继承自AbstractClass则返回该实例,否则返回null
*/
async function saveAndLoadModule(jsContent, modulesDir, fileName, AbstractClass) {
await fs.mkdir(modulesDir, { recursive: true });
const filePath = path$1.join(modulesDir, fileName);
await fs.writeFile(filePath, jsContent, "utf8");
try {
const module = await import(`${`file://${path$1.resolve(filePath)}`}?update=${Date.now()}`);
if (!("default" in module)) return null;
const instance = module.default;
if (instance instanceof AbstractClass) return instance;
return null;
} catch (error) {
console.error(`导入模块 ${fileName} 时出错:`, error);
return null;
}
}
/**
* 解析 JavaScript 代码中的 class 变量 name 的值
* @param {string} code - 输入的 JavaScript 代码
* @returns {string|null} - 解析出的 class 的 name 值,或者 null 如果没有找到
*/
function extractClassName(code) {
const match = /class\s+\w+\s+extends\s+\w+\s+{[\s\S]*?name\s*=\s*['"]([^'"]+)['"]/.exec(code);
return match ? match[1] : null;
}
//#endregion
//#region src/utils/kv_history.ts
var KVHistoryManager = class {
constructor(kvStore, name) {
this.kvStore = kvStore;
this.name = name;
}
getConversationKey(conversationId) {
return `conversation:${conversationId}`;
}
getMessageKey(conversationId, messageId) {
return `${this.getConversationKey(conversationId)}:message:${messageId}`;
}
async saveHistory(message, conversationId) {
const messageKey = this.getMessageKey(conversationId, message.id);
await this.kvStore.set(messageKey, JSON.stringify(message));
const conversationKey = this.getConversationKey(conversationId);
const messageList = JSON.parse(await this.kvStore.get(conversationKey) || "[]");
messageList.push(message.id);
await this.kvStore.set(conversationKey, JSON.stringify(messageList));
}
async getHistory(messageId, conversationId) {
if (!conversationId) return [];
if (!messageId) throw new Error("unspecified message id is not implemented yet");
let parentId = messageId;
const histories = [];
while (parentId) {
const history = await this.getOneHistory(parentId, conversationId);
if (history) {
histories.push(history);
parentId = history.parentId;
} else parentId = null;
}
return histories.reverse();
}
async deleteConversation(conversationId) {
const conversationKey = this.getConversationKey(conversationId);
const messageList = JSON.parse(await this.kvStore.get(conversationKey) || "[]");
for (const messageId of messageList) await this.kvStore.delete(this.getMessageKey(conversationId, messageId));
await this.kvStore.delete(conversationKey);
}
async getOneHistory(messageId, conversationId) {
const messageKey = this.getMessageKey(conversationId, messageId);
const messageData = await this.kvStore.get(messageKey);
return messageData ? JSON.parse(messageData) : void 0;
}
};
//#endregion
//#region src/utils/history.ts
var InMemoryHistoryManager = class extends AbstractHistoryManager {
cache;
constructor() {
super();
this.name = "InMemoryHistoryManager";
this.cache = /* @__PURE__ */ new Map();
}
async saveHistory(message, conversationId) {
if (!this.cache.has(conversationId)) this.cache.set(conversationId, /* @__PURE__ */ new Map());
this.cache.get(conversationId)?.set(message.id, message);
}
async getHistory(messageId, conversationId) {
if (!conversationId) return [];
if (!messageId) throw new Error("unspecified message id is not implemented yet");
let parentId = messageId;
const histories = [];
while (parentId) {
const history = await this.getOneHistory(parentId, conversationId);
if (history) {
histories.push(history);
parentId = history.parentId;
} else parentId = null;
}
return histories.reverse();
}
async deleteConversation(conversationId) {
this.cache.delete(conversationId);
}
async getOneHistory(messageId, conversationId) {
return this.cache.get(conversationId)?.get(messageId);
}
name;
};
var history_default = new InMemoryHistoryManager();
//#endregion
//#region src/rag/text.ts
var TextProcessor = class {
static punctuationRegex = /[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~,。!?;:()、]/g;
static stopWords = new Set([
"a",
"an",
"and",
"are",
"as",
"at",
"be",
"by",
"for",
"from",
"has",
"he",
"in",
"is",
"it",
"its",
"of",
"on",
"that",
"the",
"to",
"was",
"were",
"will",
"with",
"的",
"了",
"和",
"是",
"就",
"都",
"而",
"及",
"与",
"着",
"或",
"一个",
"没有",
"我们",
"你们",
"他们",
"很",
"但是",
"然而",
"不过",
"因为",
"所以",
"如果",
"虽然",
"尽管"
]);
/**
* 将文本分割成小段落
* @param text 输入的长文本
* @param maxLength 每个段落的最大长度
* @returns 分割后的段落数组
*/
static splitIntoChunks(text, maxLength) {
const chunks = [];
let currentChunk = "";
const sentences = text.split(/[.。!!??]+/);
for (const sentence of sentences) if ((currentChunk + sentence).length <= maxLength) currentChunk += (currentChunk ? " " : "") + sentence.trim();
else {
if (currentChunk) chunks.push(currentChunk);
currentChunk = sentence.trim();
}
if (currentChunk) chunks.push(currentChunk);
return chunks;
}
/**
* 清理和标准化文本
* @param text 输入文本
* @returns 清理后的文本
*/
static cleanText(text) {
return text.replace(this.punctuationRegex, "").replace(/\s+/g, " ").trim();
}
/**
* 简单的分词(按空格分割英文,按字符分割中文)
* @param text 输入文本
* @returns 分词后的数组
*/
static tokenize(text) {
const words = [];
let currentWord = "";
for (const char of text) if (/[\u4e00-\u9fa5]/.test(char)) {
if (currentWord) {
words.push(currentWord);
currentWord = "";
}
words.push(char);
} else if (/\s/.test(char)) {
if (currentWord) {
words.push(currentWord);
currentWord = "";
}
} else currentWord += char;
if (currentWord) words.push(currentWord);
return words;
}
/**
* 从文本中移除停用词
* @param text 输入文本
* @returns 移除停用词后的文本
*/
static removeStopWords(text) {
return this.tokenize(text).filter((word) => !this.stopWords.has(word.toLowerCase())).join(" ");
}
/**
* 提取文本中的关键词(基于简单频率)
* @param text 输入文本
* @param topN 返回的关键词数量
* @returns 关键词数组
*/
static extractKeywords(text, topN = 5) {
const words = this.tokenize(this.removeStopWords(this.cleanText(text)));
const wordFrequency = {};
for (const word of words) wordFrequency[word] = (wordFrequency[word] || 0) + 1;
return Object.entries(wordFrequency).sort((a, b) => b[1] - a[1]).slice(0, topN).map((entry) => entry[0]);
}
/**
* 计算两个文本之间的简单相似度
* @param text1 第一个文本
* @param text2 第二个文本
* @returns 相似度分数(0-1之间)
*/
static simpleSimilarity(text1, text2) {
const set1 = new Set(this.tokenize(this.removeStopWords(this.cleanText(text1))));
const set2 = new Set(this.tokenize(this.removeStopWords(this.cleanText(text2))));
const intersection = new Set([...set1].filter((x) => set2.has(x)));
const union = new Set([...set1, ...set2]);
return intersection.size / union.size;
}
};
//#endregion
//#region src/rag/result.ts
var RAGAggregator = class {
/**
* 聚合多个RAG结果
* @param results RAG结果数组
* @param maxLength 聚合结果的最大长度
* @returns 聚合后的文本
*/
static aggregate(results, maxLength = 1e3) {
const sortedResults = results.sort((a, b) => b.score - a.score);
let aggregatedContent = "";
for (const result of sortedResults) if (aggregatedContent.length + result.content.length <= maxLength) aggregatedContent += (aggregatedContent ? " " : "") + result.content;
else break;
return aggregatedContent.trim();
}
/**
* 过滤结果集
* @param results RAG结果数组
* @param minScore 最小分数阈值
* @returns 过滤后的结果数组
*/
static filterResults(results, minScore) {
return results.filter((result) => result.score >= minScore);
}
};
//#endregion
//#region src/rag/manager.ts
var RAGManager = class {
constructor(vectorDb, vectorizer) {
this.vectorDb = vectorDb;
this.vectorizer = vectorizer;
}
/**
* 添加文档到 RAG 系统
* @param document 文档文本
* @param maxNum 最大分割数
*/
async addDocument(document, maxNum = 100) {
const chunks = TextProcessor.splitIntoChunks(document, maxNum);
const vectors = await this.vectorizer.batchTextToVector(chunks);
await this.vectorDb.addVectors(vectors, chunks);
}
/**
* 执行 RAG 查询
* @param query 查询文本
* @param k 返回结果数量
* @returns 查询结果
*/
async query(query, k) {
const queryVector = await this.vectorizer.textToVector(query);
return (await this.vectorDb.search(queryVector, k)).map((r) => ({
content: r.text,
score: r.score
}));
}
/**
* 聚合检索出来的结果
* @param results 文本形式
* @param filterScore 过滤的最低分数
*/
getAggregatedResults(results, filterScore) {
if (filterScore) results = RAGAggregator.filterResults(results, filterScore);
return RAGAggregator.aggregate(results);
}
};
//#endregion
//#region src/rag/vector.ts
var AbstractVectorDatabase = class {};
//#endregion
//#region src/rag/impl/VectorizerImpl.ts
var VectorizerImpl = class {
constructor(client, model, dimensions) {
this.client = client;
this.model = model;
this.dimensions = dimensions;
}
async textToVector(text) {
return (await this.client.getEmbedding(text, {
model: this.model,
dimensions: this.dimensions
})).embeddings[0];
}
async batchTextToVector(texts) {
return (await this.client.getEmbedding(texts, {
model: this.model,
dimensions: this.dimensions
})).embeddings;
}
};
//#endregion
//#region src/rag/impl/PdfParser.ts
var PdfFileParser = class extends DocumentPathParser {
constructor() {
super();
this.type = "pdf";
this.supportedExtensions = [".pdf"];
this.initPromise = this.initializePdfParse();
}
initPromise;
valid;
type;
supportedExtensions;
async initializePdfParse() {
this.valid = await import("pdf-parse").then(() => true).catch(() => false);
}
async ready() {
await this.initPromise;
}
async parse(documentPath) {
if (this.valid) {
const buffer = fs$1.readFileSync(documentPath);
const { PDFParse } = await import("pdf-parse");
const parser = new PDFParse({ data: buffer });
const result = await parser.getText();
await parser.destroy();
return result.text;
}
throw new Error("PDF parsing is not available. To enable this feature, please install pdf-parse: npm install pdf-parse");
}
};
var PdfBufferParser = class extends DocumentFileParser {
constructor() {
super();
this.type = "pdf";
this.supportedExtensions = [".pdf"];
this.initPromise = this.initializePdfParse();
}
initPromise;
async initializePdfParse() {
try {
await import("pdf-parse");
this.valid = true;
} catch {
this.valid = false;
}
}
valid;
type;
supportedExtensions;
async ready() {
await this.initPromise;
}
async parse(buffer) {
if (this.valid) {
const { PDFParse } = await import("pdf-parse");
const parser = new PDFParse({ data: buffer });
const result = await parser.getText();
await parser.destroy();
return result.text;
}
throw new Error("PDF parsing is not available. To enable this feature, please install pdf-parse: npm install pdf-parse");
}
};
//#endregion
//#region src/rag/impl/DocxParser.ts
var import_lib$1 = /* @__PURE__ */ __toESM(require_lib(), 1);
var DocxFileParser = class extends DocumentPathParser {
constructor() {
super();
this.type = "docx";
this.supportedExtensions = ["docx"];
}
type;
supportedExtensions;
async parse(documentPath) {
return (await import_lib$1.extractRawText({ path: documentPath })).value;
}
};
var DocxBufferParser = class extends DocumentFileParser {
constructor() {
super();
this.type = "docx";
this.supportedExtensions = ["docx"];
}
type;
supportedExtensions;
async parse(buffer) {
return (await import_lib$1.extractRawText({ buffer })).value;
}
};
//#endregion
//#region src/rag/impl/PureTextParser.ts
const pureTextExtensions = [
".txt",
".text",
".md",
".markdown",
".html",
".htm",
".xml",
".yaml",
".yml",
".json",
"",
".jsx",
".ts",
".tsx",
".py",
".java",
".c",
".cpp",
".h",
".hpp",
".cs",
".go",
".rb",
".php",
".swift",
".kt",
".kts",
".scala",
".rs",
".sh",
".bash",
".pl",
".lua",
".ini",
".cfg",
".conf",
".properties",
".env",
".css",
".scss",
".sass",
".less",
".sql",
".r",
".vbs",
".ps1",
".log",
".csv",
".tsv",
".gitignore",
".gitattributes",
".npmrc",
".babelrc",
".eslintrc",
".tex"
];
var PureTextFileParser = class extends DocumentPathParser {
constructor() {
super();
this.type = "txt";
this.supportedExtensions = pureTextExtensions;
}
type;
supportedExtensions;
async parse(documentPath) {
return fs$1.readFileSync(path$2.resolve(documentPath)).toString("utf8");
}
};
var PureTextBufferParser = class extends DocumentFileParser {
constructor() {
super();
this.type = "txt";
this.supportedExtensions = pureTextExtensions;
}
type;
supportedExtensions;
async parse(buffer) {
return buffer.toString("utf8");
}
};
//#endregion
//#region src/utils/document.ts
/**
* 文档解析器管理
*/
var DocumentParserManager = class {
parsers = /* @__PURE__ */ new Map();
constructor() {
this.parsers = /* @__PURE__ */ new Map();
}
route(ext, target) {
const parsers = this.parsers.get(ext);
if (!parsers) return void 0;
return parsers.find((parser) => parser.isCompatibleType(target));
}
register(parser) {
if (!parser) return this;
parser.supportedExtensions.forEach((ext) => {
if (!this.parsers.has(ext)) this.parsers.set(ext, []);
this.parsers.get(ext).push(parser);
});
return this;
}
};
const documentParserManager = new DocumentParserManager();
documentParserManager.register(new DocxBufferParser()).register(new DocxFileParser()).register(new PureTextBufferParser()).register(new PureTextFileParser());
(async () => {
const pdfFileParser = new PdfFileParser();
await pdfFileParser.ready();
if (pdfFileParser.valid) documentParserManager.register(pdfFileParser);
const pdfBufferParser = new PdfBufferParser();
await pdfBufferParser.ready();
if (pdfBufferParser.valid) documentParserManager.register(pdfBufferParser);
})();
//#endregion
//#region src/utils/axios.ts
/**
* 创建HTTP客户端
*/
var HttpClient = class {
instance;
options;
/**
* 构造HTTP客户端
* @param options 配置选项
*/
constructor(options = {}) {
this.options = {
baseURL: "",
timeout: 1e4,
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
authorizationPrefix: "Bearer",
...options
};
this.instance = this.createAxiosInstance();
this.setupInterceptors();
}
/**
* 创建Axios实例
*/
createAxiosInstance() {
return axios_default.create({
baseURL: this.options.baseURL,
timeout: this.options.timeout,
headers: this.options.headers
});
}
/**
* 设置拦截器
*/
setupInterceptors() {
this.instance.interceptors.request.use(async (config) => {
if (this.options.onRequest) config = this.options.onRequest(config);
if (this.options.getToken && config.headers) {
const token = await this.options.getToken();
if (token) config.headers.Authorization = `${this.options.authorizationPrefix} ${token}`;
}
return config;
}, (error) => {
return Promise.reject(error);
});
this.instance.interceptors.response.use((response) => {
if (this.options.onResponse) return this.options.onResponse(response.data);
return response.data;
}, (error) => {
const apiError = this.normalizeError(error);
if (this.options.onError) return Promise.reject(this.options.onError(apiError));
return Promise.reject(apiError);
});
}
/**
* 标准化错误对象
*/
normalizeError(error) {
if (axios_default.isAxiosError(error)) {
if (error.response) return {
status: error.response.status,
data: error.response.data,
message: `Request failed with status code ${error.response.status}`,
originalError: error
};
else if (error.request) return {
request: error.request,
message: "No response received from server",
originalError: error
};
}
if (error instanceof Error) return {
message: error.message,
originalError: error
};
return {
message: "Unknown error occurred",
originalError: error instanceof Error ? error : new Error(String(error))
};
}
/**
* 更新配置
* @param options 新配置
*/
updateOptions(options) {
this.options = {
...this.options,
...options
};
this.instance = this.createAxiosInstance();
this.setupInterceptors();
}
/**
* 获取底层 Axios 实例
*/
getAxiosInstance() {
return this.instance;
}
/**
* HTTP GET 请求
*/
async get(url, config) {
return this.instance.get(url, config);
}
/**
* HTTP POST 请求
*/
async post(url, data, config) {
return this.instance.post(url, data, config);
}
/**
* HTTP PUT 请求
*/
async put(url, data, config) {
return this.instance.put(url, data, config);
}
/**
* HTTP DELETE 请求
*/
async delete(url, config) {
return this.instance.delete(url, config);
}
/**
* HTTP PATCH 请求
*/
async patch(url, data, config) {
return this.instance.patch(url, data, config);
}
};
/**
* 创建默认的HTTP客户端
*/
const createHttpClient = (options) => {
return new HttpClient(options);
};
//#endregion
//#region src/utils/config.ts
const DEFAULT_HOST = "127.0.0.1";
const DEFAULT_PORT = 48370;
var GlobalConfig = class extends EventEmitter {
/**
* jwt密钥
*/
authKey;
/**
* 监听地址
*/
host;
/**
* 监听端口
*/
port;
/**
* 是否开启调试模式
*/
debug;
/**
* 登录有效期,单位秒
*/
loginValidTime;
setAuthKey(key) {
if (key === this.authKey) return;
this.emit("change", {
key: "authKey",
newVal: key,
oldVal: this.authKey
});
this.authKey = key;
}
setHost(host) {
if (host === this.host) return;
this.emit("change", {
key: "host",
newVal: host,
oldVal: this.host
});
this.host = host;
}
setPort(port) {
if (port === this.port) return;
this.emit("change", {
key: "port",
newVal: port,
oldVal: this.port
});
this.port = port;
}
setDebug(debug) {
if (debug === this.debug) return;
this.emit("change", {
key: "debug",
newVal: debug,
oldVal: this.debug
});
this.debug = debug;
}
setLoginValidTime(time) {
if (time === this.loginValidTime) return;
this.emit("change", {
key: "loginValidTime",
newVal: time,
oldVal: this.loginValidTime
});
this.loginValidTime = time;
}
getAuthKey() {
return this.authKey;
}
getHost() {
return this.host || DEFAULT_HOST;
}
getPort() {
return this.port || DEFAULT_PORT;
}
getDebug() {
return this.debug;
}
getLoginValidTime() {
return this.loginValidTime || 1440 * 60;
}
};
//#endregion
//#region src/utils/auth.ts
var import_jsonwebtoken = /* @__PURE__ */ __toESM(require_jsonwebtoken(), 1);
var FrontEndAuthHandler = class {
token;
constructor() {}
generateToken(timeout = 300, onetime = false) {
const token = `${Math.floor(Date.now() / 1e3)}-${Math.random().toString(36).substring(2, 15)}`;
if (!onetime) {
this.token = token;
setTimeout(() => {
this.token = null;
}, timeout * 1e3);
}
return token;
}
validateToken(token) {
if (token === this.token) {
this.token = null;
return true;
}
return false;
}
static generateJWT(key) {
return import_jsonwebtoken.default.sign({ key }, key, { expiresIn: "30d" });
}
static validateJWT(key, token) {
try {
import_jsonwebtoken.default.verify(token, key);
return true;
} catch (error) {
return false;
}
}
};
//#endregion
//#region src/utils/logger.ts
function getLogger() {
return (asyncLocalStorage.getStore()?.chaite)?.getLogger() || DefaultLogger;
}
//#endregion
//#region src/utils/hash.ts
function getMd5(str) {
return crypto.createHash("md5").update(str).digest("hex");
}
//#endregion
//#region src/share/shareable.ts
/**
* T是DTO
* C是T对应的可执行的实例类型
* @interface ExecutableShareableManager
*/
var ExecutableShareableManager = class {
watcher = null;
/**
* 存储示例名称和文件名的映射
* @private
*/
instanceMap = /* @__PURE__ */ new Map();
/**
* codeDirectory是存放实际代码的目录
* @private
*/
codeDirectory;
cloudService;
constructor(type, codeDirectory, storage) {
this.type = type;
this.storage = storage;
this.codeDirectory = codeDirectory;
}
setCloudService(cloudService) {
this.cloudService = cloudService;
}
/**
* 只有可执行类型的实例才需要,如工具、处理器等。设置类不需要
* @private
*/
async initialize() {
await this.scanInstances();
await this.setupFileWatcher();
}
async setupFileWatcher() {
if (this.watcher) await this.watcher.close();
this.watcher = esm_default.watch(this.codeDirectory, {
persistent: true,
ignoreInitial: true,
ignorePermissionErrors: true,
depth: 1
}).on("all", async (event, filepath) => {
if (![
"add",
"change",
"unlink"
].includes(event)) return;
if (path$1.extname(filepath) !== ".js") return;
await this.scanInstances();
getLogger().debug(`File ${filepath} ${event}, rescanned instances`);
});
getLogger().debug(`File watcher set up for directory: ${this.codeDirectory}`);
}
async scanInstances() {
try {
const files = await promises$1.readdir(this.codeDirectory);
const newInstanceMap = /* @__PURE__ */ new Map();
for (const file of files) if (path$1.extname(file) === ".js") try {
const filePath = path$1.join(this.codeDirectory, file);
const module = await import(`file://${path$1.resolve(filePath).replace(/\\/g, "/")}?t=${Date.now()}`);
const instance = this.resolveModuleInstance(module);
if (instance && typeof instance === "object" && typeof instance.name === "string") {
const instanceName = instance.name;
getLogger().debug(`Loaded ${this.type} '${instanceName}' from file '${file}'`);
newInstanceMap.set(instanceName, file);
}
} catch (error) {
getLogger().error(`Error loading ${this.type} from file '${file}':`, error);
}
this.instanceMap = newInstanceMap;
getLogger().info(`Scanned ${this.instanceMap.size} ${this.type}: [${[...this.instanceMap.keys()].join(", ")}]`);
} catch (error) {
getLogger().error(`Error scanning ${this.type} directory:`, error);
}
}
/**
* 返回实例名字们
* @returns 实例名字列表
*/
async listInstanceNames() {
return Array.from(this.instanceMap.keys());
}
async listInstances() {
return this.storage.listItems();
}
async getInstanceT(id) {
return this.storage.getItem(id);
}
/**
* 获取实例对象而非Shareable DTO
* @param name
*/
async getInstance(name) {
const filename = this.instanceMap.get(name);
if (!filename) return void 0;
const filePath = path$1.join(this.codeDirectory, filename);
const fileURL = `file://${path$1.resolve(filePath).replace(/\\/g, "/")}`;
try {
const module = await import(fileURL + `?t=${Date.now()}`);
return this.resolveModuleInstance(module);
} catch (error) {
getLogger().error(`Error loading tool '${name}':`, error);
return;
}
}
/**
* Plugins historically used both `export default new Tool()` and
* `export class MyProcessor ...`. Resolve both shapes from the same loader.
*/
resolveModuleInstance(module) {
const candidates = [module.default, ...Object.entries(module).filter(([key]) => key !== "default").map(([, value]) => value)];
for (const candidate of candidates) {
if (candidate && typeof candidate === "object" && typeof candidate.name === "string") return candidate;
if (typeof candidate === "function") try {
const instance = new candidate();
if (instance && typeof instance === "object" && typeof instance.name === "string") return instance;
} catch {}
}
}
/**
* 新增或更新
* 有id就是更新,靠storage实现去控制,这里不管
* @param instance
* @return id
*/
async addInstance(instance) {
const cleanObj = JSON.parse(JSON.stringify(instance));
cleanObj.md5 = "";
instance.md5 = getMd5(JSON.stringify(cleanObj));
const id = await this.storage.setItem(instance.id, instance);
await this.addInstanceCode(instance.name, instance.code);
return id;
}
async addInstanceCode(name, code) {
const filename = `${name.replace(/[^a-zA-Z0-9_]/g, "_")}.js`;
const filePath = path$1.join(this.codeDirectory, filename);
await promises$1.writeFile(filePath, code);
}
async upsertInstanceT(t) {
const { name, code } = t;
if (!name || !code) throw new Error("name and code are required");
const existInstance = await this.storage.getItem(t.id);
if (existInstance) {
const existName = existInstance.name;
if (existName !== name) {
const oldFilename = this.instanceMap.get(existName);
if (oldFilename) {
getLogger().debug(`Removing old file for instance '${existName}'`);
await promises$1.unlink(path$1.join(this.codeDirectory, oldFilename));
}
}
}
return this.addInstance(t);
}
async getInstanceTByCloudId(cloudId) {
return this.storage.listItemsByEqFilter({ cloudId });
}
async renameFile(id, oldName, newName) {
const filename = `${oldName.replace(/[^a-zA-Z0-9_]/g, "_")}.js`;
if (filename) {
const filePath = path$1.join(this.codeDirectory, filename);
const newFilename = `${newName.replace(/[^a-zA-Z0-9_]/g, "_")}.js`;
const newFilePath = path$1.join(this.codeDirectory, newFilename);
await promises$1.rename(filePath, newFilePath);
}
}
async deleteInstance(id) {
const t = await this.storage.getItem(id);
if (!t) return;
const filename = this.instanceMap.get(t.name);
if (filename) {
const filePath = path$1.join(this.codeDirectory, filename);
await promises$1.unlink(filePath);
}
await this.storage.removeItem(id);
}
checkCloudService() {
if (!this.cloudService) throw new Error("Cloud service is not initialized");
return this.cloudService;
}
async shareToCloud(id) {
const service = this.checkCloudService();
const t = await this.getInstanceT(id);
if (!t) throw new Error(`${this.type} not found`);
const instance = await service.upload(t);
if (instance) {
instance.cloudId = instance.id;
instance.id = t.id;
await this.storage.setItem(id, instance);
}
return instance?.id;
}
async listFromCloud(filter, query, searchOption) {
const result = await this.checkCloudService().list(filter, query, searchOption);
const downloaded = await this.storage.listItemsByInQuery([{
field: "cloudId",
values: result.items.map((item) => item.id)
}]);
result.items.forEach((item) => {
const local = downloaded.find((d) => d.cloudId === item.id);
if (local) item.downloaded = local.id;
});
return result;
}
async getFromCloud(shareId) {
return await this.checkCloudService().download(shareId);
}
async shareP2P(name) {
const service = this.checkCloudService();
const serialized = await this.serializeInstance(name);
if (!serialized) throw new Error(`${this.type} not found`);
return service.initializeTransfer(serialized);
}
async dispose() {
if (this.watcher) {
await this.watcher.close();
this.watcher = null;
}
}
};
var NonExecutableShareableManager = class {
cloudService;
constructor(type, storage) {
this.type = type;
this.storage = storage;
}
setCloudService(cloudService) {
this.cloudService = cloudService;
}
async addInstance(instance) {
return await this.storage.setItem(instance.id, instance);
}
async deleteInstance(key) {
await this.storage.removeItem(key);
}
async listInstances() {
return await this.storage.listItems();
}
async getInstance(key) {
return await this.storage.getItem(key);
}
async upsertInstance(t) {
const { name } = t;
if (!name) throw new Error("name is required");
return this.addInstance(t);
}
async getInstanceByCloudId(cloudId) {
return this.storage.listItemsByEqFilter({ cloudId });
}
checkCloudService() {
if (!this.cloudService) throw new Error("Cloud service is not initialized");
return this.cloudService;
}
async shareToCloud(key) {
const service = this.checkCloudService();
const item = await this.storage.getItem(key);
if (!item) throw new Error(`${this.type} not found`);
return (await service.upload(item))?.id;
}
async shareP2P(key) {
const service = this.checkCloudService();
const item = await this.storage.getItem(key);
if (!item) throw new Error(`${this.type} not found`);
return service.initializeTransfer(item);
}
async getFromCloud(shareId) {
return await this.checkCloudService().download(shareId);
}
async listFromCloud(filter, query, searchOption) {
return await this.checkCloudService().list(filter, query, searchOption);
}
async deleteFromCloud(key) {
await this.checkCloudService().delete(key);
}
};
//#endregion
//#region src/share/tool.ts
var ToolManager = class ToolManager extends ExecutableShareableManager {
static instance;
constructor(toolsDirectory, storage) {
super("tool", toolsDirectory, storage);
}
setCloudService(cloudService) {
this.cloudService = cloudService;
}
static async init(toolsDirectory, storage) {
if (ToolManager.instance) return ToolManager.instance;
ToolManager.instance = new ToolManager(toolsDirectory, storage);
await ToolManager.instance.initialize();
return ToolManager.instance;
}
static async getInstance() {
if (!ToolManager.instance) return null;
return ToolManager.instance;
}
async serializeInstance(name) {
const filename = this.instanceMap.get(name);
if (!filename) return null;
const filePath = path$1.join(this.codeDirectory, filename);
try {
return new ToolDTO({
name,
code: await promises$1.readFile(filePath, "utf-8")
});
} catch (error) {
console.error(`Error serializing tool '${name}':`, error);
return null;
}
}
};
//#endregion
//#region src/channels/channels.ts
var DefaultChannelLoadBalancer = class {
constructor() {}
async getChannel(name, channels) {
const priorityGroups = this.groupByPriority(channels);
for (const group of priorityGroups) {
const availableChannels = group.filter((c) => c.status === "enabled");
if (availableChannels.length > 0) return this.selectByWeight(availableChannels);
}
throw new Error("No available channels");
}
groupByPriority(channels) {
const priorityMap = /* @__PURE__ */ new Map();
channels.forEach((channel) => {
const group = priorityMap.get(channel.priority) || [];
group.push(channel);
priorityMap.set(channel.priority, group);
});
return Array.from(priorityMap.keys()).sort((a, b) => b - a).map((priority) => priorityMap.get(priority));
}
selectByWeight(channels) {
const totalWeight = channels.reduce((sum, c) => sum + c.weight, 0);
let random = Math.random() * totalWeight;
for (const channel of channels) {
random -= channel.weight;
if (random <= 0) return channel;
}
return channels[0];
}
/**
* 获取渠道列表及其分配的数量
* generated by qwen-2.5-max
*
* @param modelName 模型名称
* @param channels 渠道列表
* @param totalQuantity 总数量
* @returns 返回一个包含渠道及其分配数量的数组
*/
async getChannels(modelName, channels, totalQuantity) {
const supportedChannels = channels.filter((channel) => channel.models.some((m) => m.name === modelName));
if (supportedChannels.length === 0) throw new Error("No channels support the specified model");
const highestPriorityGroup = this.groupByPriority(supportedChannels)[0];
if (!highestPriorityGroup || highestPriorityGroup.length === 0) throw new Error("No available channels with the highest priority");
const totalWeight = highestPriorityGroup.reduce((sum, c) => sum + c.weight, 0);
const result = [];
let remainingQuantity = totalQuantity;
for (const channel of highestPriorityGroup) {
const allocatedQuantity = Math.floor(channel.weight / totalWeight * totalQuantity);
result.push({
channel,
quantity: allocatedQuantity
});
remainingQuantity -= allocatedQuantity;
}
if (remainingQuantity > 0 && result.length > 0) result[0].quantity += remainingQuantity;
return result;
}
};
/**
* 渠道
* 每个渠道对应一个adapter,并记录客户端的options
*/
var Channel = class Channel extends AbstractShareable {
constructor(params) {
super(params);
this.modelType = "settings";
this.models = (params.models || []).map((m) => typeof m === "string" ? {
name: m,
features: ["chat", "tool"]
} : m);
if (params.adapterType) this.adapterType = params.adapterType;
if (params.options) this.options = new BaseClientOptions().fromString(JSON.stringify(params.options));
this.weight = params.weight || 1;
this.priority =