my-ai-chat-framework 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/LICENSE +21 -0
- package/README.md +305 -0
- package/README_ZH.md +401 -0
- package/dist/my-ai-chat-framework.browser.es.js +2630 -0
- package/dist/my-ai-chat-framework.browser.es.js.map +1 -0
- package/dist/my-ai-chat-framework.browser.umd.js +2634 -0
- package/dist/my-ai-chat-framework.browser.umd.js.map +1 -0
- package/dist/my-ai-chat-framework.cjs.js +2630 -0
- package/dist/my-ai-chat-framework.cjs.js.map +1 -0
- package/dist/my-ai-chat-framework.es.js +2630 -0
- package/dist/my-ai-chat-framework.es.js.map +1 -0
- package/dist/my-ai-chat-framework.node.cjs.js +1381 -0
- package/dist/my-ai-chat-framework.node.cjs.js.map +1 -0
- package/dist/my-ai-chat-framework.umd.js +2634 -0
- package/dist/my-ai-chat-framework.umd.js.map +1 -0
- package/package.json +54 -0
- package/src/core/ApiClient.js +288 -0
- package/src/core/EventEmitter.js +126 -0
- package/src/core/MessageFormatter.js +126 -0
- package/src/core/Messages.js +562 -0
- package/src/core/RequestBuilder.js +96 -0
- package/src/core/ToolManager.js +175 -0
- package/src/index.js +419 -0
- package/src/utils/index.js +21 -0
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
import MessageFormatter from './MessageFormatter.js';
|
|
2
|
+
|
|
3
|
+
class Messages {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.messages = [];
|
|
6
|
+
this.systemPrompts = [];
|
|
7
|
+
this.tools = [];
|
|
8
|
+
this.metadata = {
|
|
9
|
+
name: '',
|
|
10
|
+
createdAt: new Date(),
|
|
11
|
+
lastModified: new Date()
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// ========== 核心消息方法 ==========
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 添加消息(通用方法)
|
|
19
|
+
* @param {string} role - 角色:user/assistant/system/tool
|
|
20
|
+
* @param {string} content - 消息内容
|
|
21
|
+
* @param {object} metadata - 额外元数据
|
|
22
|
+
* @returns {number} 新消息的索引
|
|
23
|
+
*/
|
|
24
|
+
addMessage(role, content, metadata = {}) {
|
|
25
|
+
// 验证角色
|
|
26
|
+
const validRoles = ['user', 'assistant', 'system', 'tool'];
|
|
27
|
+
if (!validRoles.includes(role)) {
|
|
28
|
+
throw new Error(`无效的角色: ${role},有效值: ${validRoles.join(', ')}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 特殊处理:tool消息可以没有content(但必须有tool_call_id)
|
|
32
|
+
if (role === 'tool') {
|
|
33
|
+
// tool消息必须有tool_call_id
|
|
34
|
+
if (!metadata.tool_call_id) {
|
|
35
|
+
throw new Error('tool消息必须包含tool_call_id');
|
|
36
|
+
}
|
|
37
|
+
// tool消息的content可以为空
|
|
38
|
+
} else {
|
|
39
|
+
// 其他消息必须有内容
|
|
40
|
+
if (typeof content !== 'string') {
|
|
41
|
+
throw new Error('消息内容必须是字符串');
|
|
42
|
+
}
|
|
43
|
+
// 允许空字符串,但不允许undefined/null
|
|
44
|
+
if (content === undefined || content === null) {
|
|
45
|
+
throw new Error('消息内容不能为undefined或null');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 创建消息对象
|
|
50
|
+
const message = {
|
|
51
|
+
role,
|
|
52
|
+
content: content ? content.trim() : '', // 允许空字符串
|
|
53
|
+
timestamp: new Date()
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// 合并元数据(过滤掉undefined和null)
|
|
57
|
+
if (metadata && typeof metadata === 'object') {
|
|
58
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
59
|
+
if (value !== undefined && value !== null) {
|
|
60
|
+
message[key] = value;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return this.messages.push(message) - 1;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 添加用户消息(便捷方法)
|
|
70
|
+
*/
|
|
71
|
+
addUserMessage(content, metadata = {}) {
|
|
72
|
+
return this.addMessage('user', content, metadata);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 添加助手消息(便捷方法)
|
|
77
|
+
*/
|
|
78
|
+
addAssistantMessage(content, metadata = {}) {
|
|
79
|
+
return this.addMessage('assistant', content, metadata);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 添加系统消息(便捷方法)
|
|
84
|
+
*/
|
|
85
|
+
addSystemMessage(content, metadata = {}) {
|
|
86
|
+
return this.addMessage('system', content, metadata);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 添加工具消息(便捷方法)
|
|
91
|
+
*/
|
|
92
|
+
addToolMessage(content, toolCallId, metadata = {}) {
|
|
93
|
+
if (!toolCallId || typeof toolCallId !== 'string') {
|
|
94
|
+
throw new Error('tool_call_id不能为空');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return this.addMessage('tool', content, {
|
|
98
|
+
tool_call_id: toolCallId,
|
|
99
|
+
...metadata
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 批量添加消息
|
|
105
|
+
*/
|
|
106
|
+
addMessages(messagesArray) {
|
|
107
|
+
if (!Array.isArray(messagesArray)) {
|
|
108
|
+
throw new Error('参数必须是数组');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const indices = [];
|
|
112
|
+
for (const msg of messagesArray) {
|
|
113
|
+
if (!msg.role || !msg.content) {
|
|
114
|
+
throw new Error('消息必须包含role和content属性');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const { role, content, ...metadata } = msg;
|
|
118
|
+
const index = this.addMessage(role, content, metadata);
|
|
119
|
+
indices.push(index);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return indices;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ========== 消息查询 ==========
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 获取所有消息
|
|
129
|
+
*/
|
|
130
|
+
getMessages() {
|
|
131
|
+
return [...this.messages];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* 按角色获取消息
|
|
136
|
+
*/
|
|
137
|
+
getMessagesByRole(role) {
|
|
138
|
+
const validRoles = ['user', 'assistant', 'system', 'tool'];
|
|
139
|
+
if (!validRoles.includes(role)) {
|
|
140
|
+
throw new Error(`无效的角色: ${role}`);
|
|
141
|
+
}
|
|
142
|
+
return this.messages.filter(msg => msg.role === role);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* 获取最后一条消息
|
|
147
|
+
*/
|
|
148
|
+
getLastMessage() {
|
|
149
|
+
return this.messages.length > 0
|
|
150
|
+
? { ...this.messages[this.messages.length - 1] }
|
|
151
|
+
: null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* 获取最后一条用户消息
|
|
156
|
+
*/
|
|
157
|
+
getLastUserMessage() {
|
|
158
|
+
for (let i = this.messages.length - 1; i >= 0; i--) {
|
|
159
|
+
if (this.messages[i].role === 'user') {
|
|
160
|
+
return { ...this.messages[i] };
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* 获取最后一条助手消息
|
|
168
|
+
*/
|
|
169
|
+
getLastAssistantMessage() {
|
|
170
|
+
for (let i = this.messages.length - 1; i >= 0; i--) {
|
|
171
|
+
if (this.messages[i].role === 'assistant') {
|
|
172
|
+
return { ...this.messages[i] };
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* 获取消息数量
|
|
180
|
+
*/
|
|
181
|
+
getMessageCount() {
|
|
182
|
+
return this.messages.length;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ========== 消息修改 ==========
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* 更新消息内容
|
|
189
|
+
*/
|
|
190
|
+
updateMessage(index, content) {
|
|
191
|
+
if (!Number.isInteger(index) || index < 0 || index >= this.messages.length) {
|
|
192
|
+
throw new Error(`无效的消息索引: ${index}`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (typeof content !== 'string' || !content.trim()) {
|
|
196
|
+
throw new Error('消息内容不能为空');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
this.messages[index].content = content.trim();
|
|
200
|
+
this.messages[index].lastModified = new Date();
|
|
201
|
+
return this;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* 更新最后一条消息
|
|
206
|
+
*/
|
|
207
|
+
updateLastMessage(content) {
|
|
208
|
+
if (this.messages.length === 0) {
|
|
209
|
+
throw new Error('没有消息可以修改');
|
|
210
|
+
}
|
|
211
|
+
return this.updateMessage(this.messages.length - 1, content);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* 设置消息字段
|
|
216
|
+
*/
|
|
217
|
+
setMessageField(index, field, value) {
|
|
218
|
+
if (!Number.isInteger(index) || index < 0 || index >= this.messages.length) {
|
|
219
|
+
throw new Error(`无效的消息索引: ${index}`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
this.messages[index][field] = value;
|
|
223
|
+
this.messages[index].lastModified = new Date();
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ========== 消息删除 ==========
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* 删除消息
|
|
231
|
+
*/
|
|
232
|
+
removeMessage(index) {
|
|
233
|
+
if (!Number.isInteger(index) || index < 0 || index >= this.messages.length) {
|
|
234
|
+
throw new Error(`无效的消息索引: ${index}`);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return this.messages.splice(index, 1)[0];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* 删除最后一条消息
|
|
242
|
+
*/
|
|
243
|
+
removeLastMessage() {
|
|
244
|
+
if (this.messages.length === 0) {
|
|
245
|
+
throw new Error('没有消息可以删除');
|
|
246
|
+
}
|
|
247
|
+
return this.removeMessage(this.messages.length - 1);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* 撤回到上一条助手消息
|
|
252
|
+
*/
|
|
253
|
+
undoToAssistant() {
|
|
254
|
+
if (this.messages.length === 0) {
|
|
255
|
+
return [];
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// 找到最后一条助手消息的位置
|
|
259
|
+
let lastAssistantIndex = -1;
|
|
260
|
+
for (let i = this.messages.length - 1; i >= 0; i--) {
|
|
261
|
+
if (this.messages[i].role === 'assistant') {
|
|
262
|
+
lastAssistantIndex = i;
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (lastAssistantIndex >= 0) {
|
|
268
|
+
// 删除该助手消息之后的所有消息
|
|
269
|
+
return this.messages.splice(lastAssistantIndex + 1);
|
|
270
|
+
} else {
|
|
271
|
+
// 没有助手消息,清空所有
|
|
272
|
+
const removed = [...this.messages];
|
|
273
|
+
this.messages = [];
|
|
274
|
+
return removed;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* 是否可以撤回
|
|
280
|
+
*/
|
|
281
|
+
canUndo() {
|
|
282
|
+
return this.messages.some(msg => msg.role === 'assistant');
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* 清空所有消息
|
|
287
|
+
*/
|
|
288
|
+
clearMessages() {
|
|
289
|
+
const removed = [...this.messages];
|
|
290
|
+
this.messages = [];
|
|
291
|
+
this.metadata.lastModified = new Date();
|
|
292
|
+
return removed;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// ========== 系统提示管理 ==========
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* 添加系统提示
|
|
299
|
+
*/
|
|
300
|
+
addSystemPrompt(content, enabled = true) {
|
|
301
|
+
if (typeof content !== 'string' || !content.trim()) {
|
|
302
|
+
throw new Error('系统提示内容不能为空');
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const prompt = {
|
|
306
|
+
role: 'system',
|
|
307
|
+
content: content.trim(),
|
|
308
|
+
enabled: Boolean(enabled),
|
|
309
|
+
createdAt: new Date()
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
return this.systemPrompts.push(prompt) - 1;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* 获取启用的系统提示
|
|
317
|
+
*/
|
|
318
|
+
getEnabledSystemPrompts() {
|
|
319
|
+
return this.systemPrompts
|
|
320
|
+
.filter(prompt => prompt.enabled)
|
|
321
|
+
.map(prompt => ({ role: prompt.role, content: prompt.content }));
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* 切换系统提示状态
|
|
326
|
+
*/
|
|
327
|
+
toggleSystemPrompt(index) {
|
|
328
|
+
if (!Number.isInteger(index) || index < 0 || index >= this.systemPrompts.length) {
|
|
329
|
+
throw new Error(`无效的系统提示索引: ${index}`);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
this.systemPrompts[index].enabled = !this.systemPrompts[index].enabled;
|
|
333
|
+
return this;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* 更新系统提示内容
|
|
338
|
+
*/
|
|
339
|
+
updateSystemPrompt(index, content) {
|
|
340
|
+
if (!Number.isInteger(index) || index < 0 || index >= this.systemPrompts.length) {
|
|
341
|
+
throw new Error(`无效的系统提示索引: ${index}`);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (typeof content !== 'string' || !content.trim()) {
|
|
345
|
+
throw new Error('系统提示内容不能为空');
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
this.systemPrompts[index].content = content.trim();
|
|
349
|
+
this.systemPrompts[index].lastModified = new Date();
|
|
350
|
+
return this;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* 删除系统提示
|
|
355
|
+
*/
|
|
356
|
+
removeSystemPrompt(index) {
|
|
357
|
+
if (!Number.isInteger(index) || index < 0 || index >= this.systemPrompts.length) {
|
|
358
|
+
throw new Error(`无效的系统提示索引: ${index}`);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return this.systemPrompts.splice(index, 1)[0];
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// ========== 工具管理 ==========
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* 添加工具
|
|
368
|
+
*/
|
|
369
|
+
addTool(toolDefinition) {
|
|
370
|
+
if (typeof toolDefinition === 'object' && toolDefinition !== null) {
|
|
371
|
+
// 如果已经是格式化好的工具对象
|
|
372
|
+
if (!toolDefinition.type || toolDefinition.type !== 'function') {
|
|
373
|
+
throw new Error(`无效的工具类型,期望: 'function',实际: '${toolDefinition.type || 'undefined'}'`);
|
|
374
|
+
}
|
|
375
|
+
if (!toolDefinition.function?.name?.trim()) {
|
|
376
|
+
throw new Error('工具名称不能为空');
|
|
377
|
+
}
|
|
378
|
+
return this.tools.push(toolDefinition) - 1;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// 如果是工具定义对象,使用MessageFormatter构造
|
|
382
|
+
if (toolDefinition.name && toolDefinition.description && toolDefinition.parameters) {
|
|
383
|
+
const constructedTool = MessageFormatter.constructTool(toolDefinition);
|
|
384
|
+
return this.tools.push(constructedTool) - 1;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
throw new Error('无效的工具格式');
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* 从定义添加工具
|
|
392
|
+
*/
|
|
393
|
+
addToolFromDefinition(name, description, parameters) {
|
|
394
|
+
const tool = MessageFormatter.constructTool({ name, description, parameters });
|
|
395
|
+
return this.tools.push(tool) - 1;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* 获取所有工具
|
|
400
|
+
*/
|
|
401
|
+
getTools() {
|
|
402
|
+
return [...this.tools];
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* 删除工具
|
|
407
|
+
*/
|
|
408
|
+
removeTool(index) {
|
|
409
|
+
if (!Number.isInteger(index) || index < 0 || index >= this.tools.length) {
|
|
410
|
+
throw new Error(`无效的工具索引: ${index}`);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return this.tools.splice(index, 1)[0];
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* 清空所有工具
|
|
418
|
+
*/
|
|
419
|
+
clearTools() {
|
|
420
|
+
const removed = [...this.tools];
|
|
421
|
+
this.tools = [];
|
|
422
|
+
return removed;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// ========== 元数据管理 ==========
|
|
426
|
+
|
|
427
|
+
setName(name) {
|
|
428
|
+
if (typeof name !== 'string' || !name.trim()) {
|
|
429
|
+
throw new Error('名称不能为空');
|
|
430
|
+
}
|
|
431
|
+
this.metadata.name = name.trim();
|
|
432
|
+
this.metadata.lastModified = new Date();
|
|
433
|
+
return this;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
getName() {
|
|
437
|
+
return this.metadata.name;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// ========== 兼容性方法 ==========
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* 获取最近的消息(兼容旧方法)
|
|
444
|
+
*/
|
|
445
|
+
getRecentMessages(baseRounds, cycleRounds) {
|
|
446
|
+
const messages = this.messages.map(item => {
|
|
447
|
+
// 使用MessageFormatter.toStandardFormat来确保一致性
|
|
448
|
+
return MessageFormatter.toStandardFormat(item);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
const msgTotal = messages.length;
|
|
452
|
+
const totalRounds = msgTotal / 2;
|
|
453
|
+
|
|
454
|
+
if (!baseRounds || isNaN(baseRounds) || baseRounds <= 0) {
|
|
455
|
+
return messages;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const maxCycleRoundMultiple = cycleRounds > 0
|
|
459
|
+
? Math.floor(totalRounds / cycleRounds) * cycleRounds
|
|
460
|
+
: 0;
|
|
461
|
+
const actualRounds = baseRounds + (totalRounds - maxCycleRoundMultiple);
|
|
462
|
+
const actualMsgCount = actualRounds * 2;
|
|
463
|
+
const n = Math.max(msgTotal - actualMsgCount, 0);
|
|
464
|
+
|
|
465
|
+
return messages.slice(n);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* 获取所有格式化消息(兼容旧方法)
|
|
470
|
+
*/
|
|
471
|
+
getMessagesFormatted(baseRounds, cycleRounds) {
|
|
472
|
+
const systems = this.getEnabledSystemPrompts();
|
|
473
|
+
const hintSystem = {
|
|
474
|
+
role: 'system',
|
|
475
|
+
content: `你的名字||标题是:${this.metadata.name || '未知'}`
|
|
476
|
+
};
|
|
477
|
+
systems.unshift(hintSystem);
|
|
478
|
+
|
|
479
|
+
const recentMessages = this.getRecentMessages(baseRounds, cycleRounds);
|
|
480
|
+
return [...systems, ...recentMessages];
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// ========== 导入导出 ==========
|
|
484
|
+
|
|
485
|
+
export() {
|
|
486
|
+
return {
|
|
487
|
+
__format_version: 2,
|
|
488
|
+
exportedAt: new Date().toISOString(),
|
|
489
|
+
metadata: { ...this.metadata },
|
|
490
|
+
payload: {
|
|
491
|
+
messages: JSON.parse(JSON.stringify(this.messages)),
|
|
492
|
+
systemPrompts: JSON.parse(JSON.stringify(this.systemPrompts)),
|
|
493
|
+
tools: JSON.parse(JSON.stringify(this.tools))
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
import(data) {
|
|
499
|
+
const obj = typeof data === 'string' ? JSON.parse(data) : data;
|
|
500
|
+
const parsed = Messages.parseCompatible(obj);
|
|
501
|
+
|
|
502
|
+
this.messages = parsed.messages || [];
|
|
503
|
+
this.systemPrompts = parsed.systemPrompts || [];
|
|
504
|
+
this.tools = parsed.tools || [];
|
|
505
|
+
this.metadata = parsed.metadata || {
|
|
506
|
+
name: '',
|
|
507
|
+
createdAt: new Date(),
|
|
508
|
+
lastModified: new Date()
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
this.metadata.lastModified = new Date();
|
|
512
|
+
return this;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
static parseCompatible(obj) {
|
|
516
|
+
// 处理新格式(v2)
|
|
517
|
+
if (obj?.__format_version === 2 && obj.payload) {
|
|
518
|
+
return {
|
|
519
|
+
messages: obj.payload.messages || [],
|
|
520
|
+
systemPrompts: obj.payload.systemPrompts || [],
|
|
521
|
+
tools: obj.payload.tools || [],
|
|
522
|
+
metadata: obj.metadata || {
|
|
523
|
+
name: '',
|
|
524
|
+
createdAt: new Date(),
|
|
525
|
+
lastModified: new Date()
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// 处理旧格式(v1)
|
|
531
|
+
if (obj?.__format_version === 1 && obj.payload) {
|
|
532
|
+
return {
|
|
533
|
+
messages: obj.payload.messages || [],
|
|
534
|
+
systemPrompts: obj.payload.systems || [],
|
|
535
|
+
tools: obj.payload.tools || [],
|
|
536
|
+
metadata: {
|
|
537
|
+
name: obj.payload.hintData?.name || '',
|
|
538
|
+
createdAt: new Date(),
|
|
539
|
+
lastModified: new Date()
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// 处理更旧的格式
|
|
545
|
+
if (obj?.messages && Array.isArray(obj.messages)) {
|
|
546
|
+
return {
|
|
547
|
+
messages: obj.messages || [],
|
|
548
|
+
systemPrompts: obj.systems || [],
|
|
549
|
+
tools: obj.tools || [],
|
|
550
|
+
metadata: {
|
|
551
|
+
name: obj.hintData?.name || '',
|
|
552
|
+
createdAt: new Date(),
|
|
553
|
+
lastModified: new Date()
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
throw new Error('无法识别的聊天数据格式');
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
export default Messages;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import MessageFormatter from './MessageFormatter.js';
|
|
2
|
+
import ToolManager from './ToolManager.js';
|
|
3
|
+
import EventEmitter from './EventEmitter.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 请求构建器
|
|
7
|
+
* 负责构建符合不同API规范的请求体
|
|
8
|
+
*/
|
|
9
|
+
class RequestBuilder {
|
|
10
|
+
constructor(model, messagesInstance, config = {}) {
|
|
11
|
+
this.model = model;
|
|
12
|
+
this.messages = messagesInstance;
|
|
13
|
+
this.config = {
|
|
14
|
+
// temperature: 0.7,
|
|
15
|
+
// max_tokens: 2000,
|
|
16
|
+
// stream: false, // 默认关闭流式传输
|
|
17
|
+
...config
|
|
18
|
+
};
|
|
19
|
+
this.toolManager = null; // 可选的ToolManager引用
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 设置ToolManager引用
|
|
24
|
+
*/
|
|
25
|
+
setToolManager(toolManager) {
|
|
26
|
+
this.toolManager = toolManager;
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 构建OpenAI兼容格式的请求体
|
|
32
|
+
*/
|
|
33
|
+
buildOpenAIFormat(baseRounds, cycleRounds) {
|
|
34
|
+
// 使用新的MessageFormatter方法
|
|
35
|
+
const formattedMessages = MessageFormatter.formatMessages(
|
|
36
|
+
this.messages,
|
|
37
|
+
baseRounds,
|
|
38
|
+
cycleRounds
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const request = {
|
|
42
|
+
model: this.model,
|
|
43
|
+
messages: formattedMessages,
|
|
44
|
+
...this.config
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// 优先从ToolManager获取工具定义,其次从Messages获取
|
|
48
|
+
let tools = [];
|
|
49
|
+
if (this.toolManager && this.toolManager.hasTools()) {
|
|
50
|
+
tools = this.toolManager.getToolDefinitions();
|
|
51
|
+
} else {
|
|
52
|
+
tools = this.messages.getTools();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (tools && tools.length > 0) {
|
|
56
|
+
request.tools = tools;
|
|
57
|
+
request.tool_choice = 'auto';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return request;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 构建请求体并返回JSON字符串
|
|
65
|
+
*/
|
|
66
|
+
toJSON(baseRounds, cycleRounds) {
|
|
67
|
+
const request = this.buildOpenAIFormat(baseRounds, cycleRounds);
|
|
68
|
+
return JSON.stringify(request);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 构建请求体并返回对象
|
|
73
|
+
*/
|
|
74
|
+
toObject(baseRounds, cycleRounds) {
|
|
75
|
+
return this.buildOpenAIFormat(baseRounds, cycleRounds);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 设置配置项
|
|
80
|
+
*/
|
|
81
|
+
setConfig(key, value) {
|
|
82
|
+
this.config[key] = value;
|
|
83
|
+
return this; // 支持链式调用
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 批量设置配置项
|
|
88
|
+
*/
|
|
89
|
+
setConfigs(configs) {
|
|
90
|
+
Object.assign(this.config, configs);
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export default RequestBuilder;
|
|
96
|
+
|