aichat-core
Version:
AI 流式聊天业务核心TS模型封装及业务实现模块
498 lines (497 loc) • 26.4 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __asyncValues = (this && this.__asyncValues) || function (o) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var m = o[Symbol.asyncIterator], i;
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
import OpenAI from "openai";
import McpClient from "./McpClient";
var LLMClient = (function () {
function LLMClient(mcpServer, mcpClientName, apiKey, baseUrl, modelName) {
if (mcpServer === void 0) { mcpServer = ""; }
if (mcpClientName === void 0) { mcpClientName = ""; }
this.mcpServer = "";
this.tools = [];
this.initMcpState = false;
this.thinkState = false;
this.logDebug = false;
this.llm = new OpenAI({
apiKey: apiKey,
baseURL: baseUrl,
dangerouslyAllowBrowser: true,
});
this.modelName = modelName;
this.toolChoice = "auto";
if (mcpServer !== "") {
this.mcpServer = mcpServer;
this.mcpClient = new McpClient(mcpClientName);
}
}
LLMClient.prototype.initMcpServer = function () {
return __awaiter(this, void 0, void 0, function () {
var _a, error_1;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!this.mcpClient) {
return [2];
}
_b.label = 1;
case 1:
_b.trys.push([1, 4, , 5]);
return [4, this.mcpClient.connect2Server(this.mcpServer)];
case 2:
_b.sent();
console.log("=====================1.连接mcp服务成功");
_a = this;
return [4, this.mcpClient.getTools()];
case 3:
_a.tools = _b.sent();
console.log("=====================2.获取mcp工具列表成功,共:" + this.tools.length);
this.initMcpState = true;
return [3, 5];
case 4:
error_1 = _b.sent();
this.tools = [];
return [3, 5];
case 5: return [2];
}
});
});
};
LLMClient.prototype.chatStreamLLMV2 = function (messages_1, onContentCallBack_1, onCallToolsCallBack_1, onCallToolResultCallBack_1, callBackMessage_1, controllerRef_1) {
return __awaiter(this, arguments, void 0, function (messages, onContentCallBack, onCallToolsCallBack, onCallToolResultCallBack, callBackMessage, controllerRef, loop) {
var stream, _toolCalls, _a, stream_1, stream_1_1, chunk, usage, _choices, _choiceMessage, newCallBackMessage, finishReason, _choiceMessage, newCallBackMessage, toolCalls, _choices, _choiceMessage, newCallBackMessage, choices, e_1_1;
var _b, e_1, _c, _d;
var _e;
if (loop === void 0) { loop = 1; }
return __generator(this, function (_f) {
switch (_f.label) {
case 0:
console.log("=====================\u5F00\u59CB\u7B2C".concat(loop, "\u8F6E\u804A\u5929"));
return [4, this.genLLMStream(messages, controllerRef)];
case 1:
stream = _f.sent();
if (!(stream &&
typeof stream[Symbol.asyncIterator] === LLMClient.TYPE_FUNCTION)) return [3, 18];
_toolCalls = [];
_f.label = 2;
case 2:
_f.trys.push([2, 11, 12, 17]);
_a = true, stream_1 = __asyncValues(stream);
_f.label = 3;
case 3: return [4, stream_1.next()];
case 4:
if (!(stream_1_1 = _f.sent(), _b = stream_1_1.done, !_b)) return [3, 10];
_d = stream_1_1.value;
_a = false;
chunk = _d;
if (this.logDebug) {
console.log("chunk", chunk);
}
callBackMessage.timed = chunk.created;
callBackMessage.model = chunk.model;
usage = chunk.usage;
if (usage) {
console.log("=====================\u7B2C".concat(loop, "\u8F6E\u6D41\u5F0F\u804A\u5929\u7ED3\u675F\uFF0Cusage : "), usage);
_choices = callBackMessage.choices;
if (_choices && _choices.length > 0) {
_choiceMessage = this.filterChoiceMessage(callBackMessage, loop);
_choiceMessage.index = loop;
_choiceMessage.thinking = 2;
_choiceMessage.reasoning_content = "";
_choiceMessage.content = "";
_choiceMessage.usage = {
completion_tokens: usage.completion_tokens,
prompt_tokens: usage.prompt_tokens,
total_tokens: usage.total_tokens,
};
newCallBackMessage = JSON.parse(JSON.stringify(callBackMessage));
onContentCallBack(newCallBackMessage);
}
return [3, 9];
}
finishReason = (_e = chunk.choices[0].finish_reason) !== null && _e !== void 0 ? _e : "";
if (!(finishReason !== "")) return [3, 6];
return [4, this.dealFinishReason(finishReason, _toolCalls, messages, onContentCallBack, onCallToolsCallBack, onCallToolResultCallBack, callBackMessage, controllerRef, loop)];
case 5:
_f.sent();
_choiceMessage = this.filterChoiceMessage(callBackMessage, loop);
_choiceMessage.content = "";
_choiceMessage.reasoning_content = "";
callBackMessage.finishReason = finishReason;
newCallBackMessage = JSON.parse(JSON.stringify(callBackMessage));
onContentCallBack(newCallBackMessage);
return [3, 9];
case 6:
toolCalls = chunk.choices[0].delta.tool_calls;
if (!(toolCalls && toolCalls.length > 0)) return [3, 7];
_choices = callBackMessage.choices;
if (_choices && _choices.length > 0) {
_choiceMessage = this.filterChoiceMessage(callBackMessage, loop);
if (!_choiceMessage.toolsCallDes) {
_choiceMessage.toolsCallDes = LLMClient.TOOLS_CALLING_DESC;
_choiceMessage.content = "";
_choiceMessage.reasoning_content = "";
newCallBackMessage = JSON.parse(JSON.stringify(callBackMessage));
onContentCallBack(newCallBackMessage);
}
}
this.dealToolCalls(toolCalls, _toolCalls);
return [3, 9];
case 7:
choices = chunk.choices;
return [4, this.dealTextContent(choices, onContentCallBack, callBackMessage, loop)];
case 8:
_f.sent();
_f.label = 9;
case 9:
_a = true;
return [3, 3];
case 10: return [3, 17];
case 11:
e_1_1 = _f.sent();
e_1 = { error: e_1_1 };
return [3, 17];
case 12:
_f.trys.push([12, , 15, 16]);
if (!(!_a && !_b && (_c = stream_1.return))) return [3, 14];
return [4, _c.call(stream_1)];
case 13:
_f.sent();
_f.label = 14;
case 14: return [3, 16];
case 15:
if (e_1) throw e_1.error;
return [7];
case 16: return [7];
case 17: return [3, 19];
case 18:
console.error("Stream is not async iterable.");
_f.label = 19;
case 19: return [2];
}
});
});
};
LLMClient.prototype.genLLMStream = function (messages, controllerRef) {
return __awaiter(this, void 0, void 0, function () {
var stream, _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!(!this.tools || this.tools.length == 0)) return [3, 2];
return [4, this.llm.chat.completions.create({
model: this.modelName,
messages: messages,
stream: true,
temperature: 0.0,
}, {
signal: controllerRef && controllerRef.signal,
})];
case 1:
_a = _b.sent();
return [3, 4];
case 2: return [4, this.llm.chat.completions.create({
model: this.modelName,
messages: messages,
tools: this.convert2OpenAiTools(this.tools),
stream: true,
temperature: 0.0,
tool_choice: this.toolChoice,
}, {
signal: controllerRef && controllerRef.signal,
})];
case 3:
_a = _b.sent();
_b.label = 4;
case 4:
stream = _a;
return [2, stream];
}
});
});
};
LLMClient.prototype.filterChoiceMessage = function (callBackMessage, index) {
var _a;
var _choices = (_a = callBackMessage.choices) !== null && _a !== void 0 ? _a : [];
if (_choices && _choices.length > 0) {
var _choiceMessages = _choices.filter(function (item) { return item.index === index; });
if (_choiceMessages && _choiceMessages.length > 0) {
return _choiceMessages[0];
}
}
var initChoiceMessage = {
index: index,
content: "",
};
_choices.push(initChoiceMessage);
return initChoiceMessage;
};
LLMClient.prototype.dealFinishReason = function (finishReason_1, toolCalls_1, messages_1, onContentCallBack_1, onCallToolsCallBack_1, onCallToolResultCallBack_1, callBackMessage_1, controllerRef_1) {
return __awaiter(this, arguments, void 0, function (finishReason, toolCalls, messages, onContentCallBack, onCallToolsCallBack, onCallToolResultCallBack, callBackMessage, controllerRef, loop) {
var _choiceMessage, bSuccess;
if (loop === void 0) { loop = 0; }
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(finishReason === LLMClient.REASON_STOP)) return [3, 1];
console.log("=====================\u7B2C".concat(loop, "\u8F6E\u6D41\u5F0F\u804A\u5929\u7ED3\u675F\uFF0C\u7ED3\u675F\u539F\u56E0(\u8FD9\u4E2A\u65F6\u5019\u9700\u8981\u4E00\u4E2A\u56DE\u8C03)\uFF1A").concat(finishReason));
return [3, 5];
case 1:
if (!(finishReason === LLMClient.REASON_TOO_CALLS)) return [3, 5];
console.log("=====================\u7B2C".concat(loop, "\u8F6E\u9009\u53D6\u5DE5\u5177\u7ED3\u675F\uFF0C\u7ED3\u675F\u539F\u56E0(\u8FD9\u4E2A\u65F6\u5019\u9700\u8981\u6267\u884C\u5DE5\u5177):").concat(finishReason));
console.log("=====================\u7B2C".concat(loop, "\u8F6E\u5DE5\u5177\u8BE6\u60C5\uFF1A"), toolCalls);
if (!(toolCalls && toolCalls.length > 0)) return [3, 5];
_choiceMessage = this.filterChoiceMessage(callBackMessage, loop);
_choiceMessage.content = "";
_choiceMessage.reasoning_content = "";
onCallToolsCallBack && onCallToolsCallBack(toolCalls);
return [4, this.reBuildMessages(toolCalls, messages, onCallToolResultCallBack, callBackMessage, loop)];
case 2:
bSuccess = _a.sent();
if (!bSuccess) return [3, 4];
console.log("\u7B2C".concat(loop, "\u8F6E\u5BF9\u8BDD\u7ED3\u675F\uFF0C\u6D88\u606F\u4E0A\u4E0B\u6587\uFF1A"), messages);
loop++;
_choiceMessage.toolsCallDes = LLMClient.TOOLS_CALLED_DESC;
return [4, this.chatStreamLLMV2(messages, onContentCallBack, onCallToolsCallBack, onCallToolResultCallBack, callBackMessage, controllerRef, loop)];
case 3:
_a.sent();
return [3, 5];
case 4: throw new Error("执行工具调用构建messages异常,请排查!");
case 5: return [2];
}
});
});
};
LLMClient.prototype.reBuildMessages = function (toolCalls_1, messages_1, onCallToolResultCallBack_1, callBackMessage_1) {
return __awaiter(this, arguments, void 0, function (toolCalls, messages, onCallToolResultCallBack, callBackMessage, loop) {
var _toolCalls, index, _i, toolCalls_2, toolCall, toolCalls_3, assistantMessage, methodName, methodArgs, callResult, toolMessage, _choiceMessage, error_2;
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
if (loop === void 0) { loop = 0; }
return __generator(this, function (_k) {
switch (_k.label) {
case 0:
if (!this.mcpClient) {
return [2, false];
}
_k.label = 1;
case 1:
_k.trys.push([1, 6, , 7]);
_toolCalls = [];
index = 0;
_i = 0, toolCalls_2 = toolCalls;
_k.label = 2;
case 2:
if (!(_i < toolCalls_2.length)) return [3, 5];
toolCall = toolCalls_2[_i];
toolCalls_3 = [];
toolCalls_3.push(this.buildMessageToolCall(toolCall));
assistantMessage = {
role: LLMClient.ROLE_AI,
tool_calls: toolCalls_3,
};
messages.push(assistantMessage);
methodName = (_b = (_a = toolCall.function) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "";
methodArgs = (_d = (_c = toolCall.function) === null || _c === void 0 ? void 0 : _c.arguments) !== null && _d !== void 0 ? _d : "{}";
return [4, this.mcpClient.callTool({
id: (_e = toolCall.id) !== null && _e !== void 0 ? _e : "",
function: {
name: methodName,
arguments: methodArgs,
},
type: (_f = toolCall.type) !== null && _f !== void 0 ? _f : LLMClient.TYPE_FUNCTION,
})];
case 3:
callResult = _k.sent();
if (this.logDebug) {
console.log("".concat(methodName, "-callResult: ") + callResult);
}
onCallToolResultCallBack(methodName, callResult);
toolMessage = {
content: callResult,
role: LLMClient.ROLE_TOOL,
tool_call_id: (_g = toolCall.id) !== null && _g !== void 0 ? _g : "",
};
messages.push(toolMessage);
_toolCalls.push({
id: (_h = toolCall.id) !== null && _h !== void 0 ? _h : "",
index: (_j = toolCall.index) !== null && _j !== void 0 ? _j : index,
name: methodName,
arguments: methodArgs,
content: callResult,
});
index++;
_k.label = 4;
case 4:
_i++;
return [3, 2];
case 5:
_choiceMessage = this.filterChoiceMessage(callBackMessage, loop);
_choiceMessage.tools = _toolCalls;
return [2, true];
case 6:
error_2 = _k.sent();
console.log("error : " + error_2);
return [2, false];
case 7: return [2];
}
});
});
};
LLMClient.prototype.buildMessageToolCall = function (toolCall) {
var _a, _b, _c, _d, _e, _f;
return {
id: (_a = toolCall.id) !== null && _a !== void 0 ? _a : "",
type: (_b = toolCall.type) !== null && _b !== void 0 ? _b : "function",
function: {
name: (_d = (_c = toolCall.function) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : "",
arguments: (_f = (_e = toolCall.function) === null || _e === void 0 ? void 0 : _e.arguments) !== null && _f !== void 0 ? _f : "",
},
};
};
LLMClient.prototype.dealToolCalls = function (toolCalls, finalToolCalls) {
for (var i = 0; i < toolCalls.length; i++) {
var toolCall = toolCalls[i];
var index = toolCall.index;
if (finalToolCalls.length < index + 1) {
finalToolCalls.push(toolCall);
}
else {
var tool = finalToolCalls[index];
if (tool.function &&
toolCall.function &&
typeof toolCall.function.arguments === "string") {
tool.function.arguments += toolCall.function.arguments;
}
}
}
};
LLMClient.prototype.dealTextContent = function (choices_1, onContentCallBack_1, callBackMessage_1) {
return __awaiter(this, arguments, void 0, function (choices, onContentCallBack, callBackMessage, loop) {
var delta, _choiceMessage, content, newCallBackMessage;
if (loop === void 0) { loop = 0; }
return __generator(this, function (_a) {
if (choices && choices.length > 0) {
delta = choices[0].delta;
if (!delta) {
return [2];
}
_choiceMessage = this.filterChoiceMessage(callBackMessage, loop);
if (delta.reasoning_content) {
_choiceMessage.thinking = 1;
_choiceMessage.reasoning_content = delta.reasoning_content;
}
if (delta.content) {
content = delta.content;
if (content.startsWith(LLMClient.THINGKING_START_TAG)) {
this.thinkState = true;
return [2];
}
else if (content.endsWith(LLMClient.THINGKING_END_TAG)) {
this.thinkState = false;
return [2];
}
if (this.thinkState) {
_choiceMessage.thinking = 1;
_choiceMessage.reasoning_content = content;
}
else {
_choiceMessage.thinking = 2;
_choiceMessage.content = content;
_choiceMessage.reasoning_content = "";
}
}
newCallBackMessage = JSON.parse(JSON.stringify(callBackMessage));
onContentCallBack(newCallBackMessage);
}
return [2];
});
});
};
LLMClient.prototype.listTools = function () {
return this.tools;
};
LLMClient.prototype.convert2OpenAiTools = function (tools) {
if (!tools || tools.length == 0) {
return [];
}
var openAiTools = [];
for (var i = 0; i < tools.length; i++) {
openAiTools.push({
type: LLMClient.TYPE_FUNCTION,
function: {
name: tools[i].name,
description: tools[i].description,
parameters: tools[i].input_schema,
},
});
}
return openAiTools;
};
LLMClient.prototype.getLogDebug = function () {
return this.logDebug;
};
LLMClient.prototype.setLogDebug = function (logDebug) {
if (logDebug === void 0) { logDebug = false; }
this.logDebug = logDebug;
};
LLMClient.prototype.getToolChoice = function () {
return this.toolChoice;
};
LLMClient.prototype.setToolChoice = function (toolChoice) {
this.toolChoice = toolChoice;
};
LLMClient.CONTENT_THINKING = "thinking";
LLMClient.TYPE_FUNCTION = "function";
LLMClient.TYPE_STRING = "string";
LLMClient.REASON_STOP = "stop";
LLMClient.REASON_TOO_CALLS = "tool_calls";
LLMClient.ROLE_AI = "assistant";
LLMClient.ROLE_SYSTEM = "system";
LLMClient.ROLE_USER = "user";
LLMClient.ROLE_TOOL = "tool";
LLMClient.THINGKING_START_TAG = "<think>";
LLMClient.THINGKING_END_TAG = "</think>";
LLMClient.TOOLS_CALLING_DESC = "工具正在调用的路上,请稍等...";
LLMClient.TOOLS_CALLED_DESC = "工具调用已完成,结果如下:";
return LLMClient;
}());
export default LLMClient;