my-ai-chat-framework 1.0.2 → 2.0.0
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/.env +15 -0
- package/README.md +70 -268
- package/dist/my-ai-chat-framework.browser.es.js +427 -2627
- package/dist/my-ai-chat-framework.browser.es.js.map +1 -1
- package/dist/my-ai-chat-framework.browser.umd.js +442 -2633
- package/dist/my-ai-chat-framework.browser.umd.js.map +1 -1
- package/dist/my-ai-chat-framework.node.cjs.js +436 -1378
- package/dist/my-ai-chat-framework.node.cjs.js.map +1 -1
- package/package.json +15 -32
- package/src/adapters/openai.js +130 -0
- package/src/core/ChatService.js +110 -0
- package/src/core/EventEmitter.js +32 -126
- package/src/core/MessageStore.js +73 -0
- package/src/index.js +10 -414
- package/src/plugins/tool-calling.js +119 -0
- package/test.js +107 -0
- package/README_ZH.md +0 -401
- package/dist/my-ai-chat-framework.cjs.js +0 -2630
- package/dist/my-ai-chat-framework.cjs.js.map +0 -1
- package/dist/my-ai-chat-framework.es.js +0 -2630
- package/dist/my-ai-chat-framework.es.js.map +0 -1
- package/dist/my-ai-chat-framework.umd.js +0 -2634
- package/dist/my-ai-chat-framework.umd.js.map +0 -1
- package/src/core/ApiClient.js +0 -288
- package/src/core/MessageFormatter.js +0 -126
- package/src/core/Messages.js +0 -562
- package/src/core/RequestBuilder.js +0 -96
- package/src/core/ToolManager.js +0 -175
- package/src/utils/index.js +0 -21
package/src/core/EventEmitter.js
CHANGED
|
@@ -1,126 +1,32 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
this.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
* 触发事件
|
|
34
|
-
* @param {string} eventName --要触发的事件名称
|
|
35
|
-
* @param {any} data --传递给回调函数的数据
|
|
36
|
-
*/
|
|
37
|
-
emit(eventName, data) {
|
|
38
|
-
//获取这个事件的所有回调函数
|
|
39
|
-
const callbacks = this.events[eventName]
|
|
40
|
-
|
|
41
|
-
//仅在有回调函数时调用他们,否则提前退出(可以这么写吧?少一层嵌套)
|
|
42
|
-
if (!callbacks) return
|
|
43
|
-
|
|
44
|
-
//使用slice()创建副本,放置在循环中修改数组导致问题
|
|
45
|
-
const callbakesCopy = callbacks.slice()
|
|
46
|
-
|
|
47
|
-
for (let i = 0; i < callbakesCopy.length; i++) {
|
|
48
|
-
try {
|
|
49
|
-
//执行回调函数,并传入数据
|
|
50
|
-
callbakesCopy[i](data)
|
|
51
|
-
} catch (error) {
|
|
52
|
-
// 如果某个回调出错,不影响其他回调
|
|
53
|
-
console.error(`事件 ${eventName} 的回调函数执行出错:`, error)
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* 取消监听事件
|
|
60
|
-
* @param {string} eventName --要取消的事件名称
|
|
61
|
-
* @param {Function} callback --要移除的回调函数
|
|
62
|
-
*/
|
|
63
|
-
off(eventName, callback) {
|
|
64
|
-
const callbacks = this.events[eventName]
|
|
65
|
-
|
|
66
|
-
//判断一下防止报错
|
|
67
|
-
if (!callbacks) return
|
|
68
|
-
|
|
69
|
-
//过滤掉要移除的回调函数
|
|
70
|
-
this.events[eventName] = callbacks.filter(item => item !== callback)
|
|
71
|
-
|
|
72
|
-
// 如果这个事件没有监听器了,删除这个事件
|
|
73
|
-
if (this.events[eventName].length === 0) {
|
|
74
|
-
delete this.events[eventName]
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* 只监听一次事件(触发后自动取消)
|
|
80
|
-
* @param {string} eventName - 事件名称
|
|
81
|
-
* @param {Function} callback - 回调函数
|
|
82
|
-
*/
|
|
83
|
-
once(evenName, callback) {
|
|
84
|
-
// 创建一个包装函数,执行完成后自动取消
|
|
85
|
-
const onceCallback = (data) => {
|
|
86
|
-
//先取消监听
|
|
87
|
-
this.off(evenName, onceCallback)
|
|
88
|
-
//在执行原回调
|
|
89
|
-
callback(data)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
//监听包装后的函数
|
|
93
|
-
this.on(evenName, onceCallback)
|
|
94
|
-
|
|
95
|
-
//返回取消函数
|
|
96
|
-
return () => this.off(evenName, onceCallback)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* 移除某个事件的所有监听器
|
|
101
|
-
* @param {string} eventName - 事件名称
|
|
102
|
-
*/
|
|
103
|
-
removeAllListeners(eventName) {
|
|
104
|
-
if (eventName) {
|
|
105
|
-
// 移除指定事件的所有监听器
|
|
106
|
-
delete this.events[eventName]
|
|
107
|
-
} else {
|
|
108
|
-
// 如果没有指定事件名,移除所有事件的监听器
|
|
109
|
-
this.events = {}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* 获取某个事件的所有监听器数量
|
|
115
|
-
* @param {string} eventName - 事件名称
|
|
116
|
-
* @returns {number} 监听器数量
|
|
117
|
-
*/
|
|
118
|
-
listenerCount(eventName) {
|
|
119
|
-
const callbacks = this.events[eventName]
|
|
120
|
-
return callbacks ? callbacks.length : 0
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
//导出EventEmiter类
|
|
126
|
-
export default EventEmitter
|
|
1
|
+
/**
|
|
2
|
+
* 极简事件发射器
|
|
3
|
+
*/
|
|
4
|
+
export class EventEmitter {
|
|
5
|
+
constructor() {
|
|
6
|
+
this._events = new Map();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
on(event, handler) {
|
|
10
|
+
if (!this._events.has(event)) this._events.set(event, []);
|
|
11
|
+
this._events.get(event).push(handler);
|
|
12
|
+
return () => this.off(event, handler);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
off(event, handler) {
|
|
16
|
+
if (!this._events.has(event)) return;
|
|
17
|
+
const handlers = this._events.get(event).filter(h => h !== handler);
|
|
18
|
+
if (handlers.length) this._events.set(event, handlers);
|
|
19
|
+
else this._events.delete(event);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
emit(event, data) {
|
|
23
|
+
if (!this._events.has(event)) return;
|
|
24
|
+
for (const handler of this._events.get(event)) {
|
|
25
|
+
try {
|
|
26
|
+
handler(data);
|
|
27
|
+
} catch (err) {
|
|
28
|
+
console.error(`事件 ${event} 处理出错:`, err);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 消息存储 - 极简实现
|
|
3
|
+
* 每条消息格式:
|
|
4
|
+
* {
|
|
5
|
+
* id?: string,
|
|
6
|
+
* role: 'user'|'assistant'|'system'|'tool',
|
|
7
|
+
* content: string,
|
|
8
|
+
* toolCalls?: Array,
|
|
9
|
+
* toolCallId?: string,
|
|
10
|
+
* timestamp?: number,
|
|
11
|
+
* metadata?: any
|
|
12
|
+
* }
|
|
13
|
+
*/
|
|
14
|
+
export class MessageStore {
|
|
15
|
+
constructor() {
|
|
16
|
+
this._messages = [];
|
|
17
|
+
this._idCounter = 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
add(message) {
|
|
21
|
+
const msg = {
|
|
22
|
+
id: message.id || `msg_${Date.now()}_${++this._idCounter}`,
|
|
23
|
+
timestamp: message.timestamp || Date.now(),
|
|
24
|
+
...message
|
|
25
|
+
};
|
|
26
|
+
this._messages.push(msg);
|
|
27
|
+
return msg;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
addUser(content, metadata = {}) {
|
|
31
|
+
return this.add({ role: 'user', content, metadata });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
addAssistant(content, metadata = {}) {
|
|
35
|
+
return this.add({ role: 'assistant', content, metadata });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
addSystem(content, metadata = {}) {
|
|
39
|
+
return this.add({ role: 'system', content, metadata });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
addTool(content, toolCallId, metadata = {}) {
|
|
43
|
+
return this.add({ role: 'tool', content, toolCallId, metadata });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
getLast() {
|
|
47
|
+
return this._messages[this._messages.length - 1] || null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
getAll() {
|
|
51
|
+
return [...this._messages];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
clear() {
|
|
55
|
+
this._messages = [];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 撤回最后一条助手消息及其后的所有消息(用于工具调用循环)
|
|
59
|
+
undoToLastAssistant() {
|
|
60
|
+
let lastAssistantIndex = -1;
|
|
61
|
+
for (let i = this._messages.length - 1; i >= 0; i--) {
|
|
62
|
+
if (this._messages[i].role === 'assistant') {
|
|
63
|
+
lastAssistantIndex = i;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (lastAssistantIndex >= 0) {
|
|
68
|
+
const removed = this._messages.splice(lastAssistantIndex + 1);
|
|
69
|
+
return removed;
|
|
70
|
+
}
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,419 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { ChatService } from './core/ChatService.js';
|
|
2
|
+
import { MessageStore } from './core/MessageStore.js';
|
|
3
|
+
import { EventEmitter } from './core/EventEmitter.js';
|
|
4
|
+
import { openaiAdapter } from './adapters/openai.js';
|
|
5
|
+
import { toolCallingPlugin } from './plugins/tool-calling.js';
|
|
3
6
|
|
|
4
|
-
|
|
5
|
-
import RequestBuilder from './core/RequestBuilder.js';
|
|
6
|
-
import ApiClient from './core/ApiClient.js';
|
|
7
|
-
import EventEmitter from './core/EventEmitter.js';
|
|
8
|
-
import MessageFormatter from './core/MessageFormatter.js';
|
|
9
|
-
import ToolManager from './core/ToolManager.js'; // 新增导入
|
|
7
|
+
export { ChatService, MessageStore, EventEmitter, openaiAdapter, toolCallingPlugin };
|
|
10
8
|
|
|
11
|
-
// 导出所有核心类
|
|
12
|
-
export { Messages, RequestBuilder, ApiClient, EventEmitter, MessageFormatter, ToolManager };
|
|
13
|
-
|
|
14
|
-
// ChatService类,继承EventEmitter
|
|
15
|
-
class ChatService extends EventEmitter {
|
|
16
|
-
constructor(apiKey, model = 'deepseek-chat', config = {}) {
|
|
17
|
-
super();
|
|
18
|
-
|
|
19
|
-
this.messages = new Messages();
|
|
20
|
-
this.apiClient = new ApiClient(apiKey);
|
|
21
|
-
this.requestBuilder = new RequestBuilder(model, this.messages, config);
|
|
22
|
-
this.toolManager = new ToolManager(); // 新增:工具管理器
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
this._setupDefaultListeners();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
_setupDefaultListeners() {
|
|
29
|
-
// 监听API客户端的事件
|
|
30
|
-
this.apiClient.on('request-start', (data) => {
|
|
31
|
-
this.emit('request-start', data);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
this.apiClient.on('request-success', (data) => {
|
|
35
|
-
this.emit('request-success', data);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
this.apiClient.on('request-error', (data) => {
|
|
39
|
-
this.emit('request-error', data);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
this.apiClient.on('stream-chunk', (data) => {
|
|
43
|
-
this.emit('stream-chunk', data);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// 监听工具管理器的事件
|
|
47
|
-
this.toolManager.on('tool-execute-start', (data) => {
|
|
48
|
-
this.emit('tool-execute-start', data);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
this.toolManager.on('tool-execute-success', (data) => {
|
|
52
|
-
this.emit('tool-execute-success', data);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
this.toolManager.on('tool-execute-error', (data) => {
|
|
56
|
-
this.emit('tool-execute-error', data);
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* 注册工具
|
|
62
|
-
*/
|
|
63
|
-
registerTool(name, definition, executor) {
|
|
64
|
-
// 1. 在ToolManager中注册
|
|
65
|
-
this.toolManager.registerTool(name, definition, executor);
|
|
66
|
-
|
|
67
|
-
// 2. 在Messages中添加工具定义(用于发送给AI)
|
|
68
|
-
this.messages.addTool(definition);
|
|
69
|
-
|
|
70
|
-
return this; // 支持链式调用
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* 发送消息(支持工具调用)
|
|
75
|
-
*/
|
|
76
|
-
async send(userMessage, options = {}) {
|
|
77
|
-
try {
|
|
78
|
-
// 触发事件:开始发送
|
|
79
|
-
this.emit('sending', {
|
|
80
|
-
role: 'user',
|
|
81
|
-
content: userMessage,
|
|
82
|
-
timestamp: new Date()
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
// 添加用户消息
|
|
86
|
-
this.messages.addUserMessage(userMessage);
|
|
87
|
-
|
|
88
|
-
// 构建请求体(会自动包含工具定义)
|
|
89
|
-
// 注意:这里需要确保RequestBuilder的配置正确
|
|
90
|
-
const requestBody = this.requestBuilder.toJSON(
|
|
91
|
-
options.baseRounds,
|
|
92
|
-
options.cycleRounds
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
// 发送请求
|
|
96
|
-
const response = await this.apiClient.send(requestBody);
|
|
97
|
-
const aiMessage = response.choices[0].message;
|
|
98
|
-
|
|
99
|
-
// 检查是否有工具调用
|
|
100
|
-
if (aiMessage.tool_calls && aiMessage.tool_calls.length > 0) {
|
|
101
|
-
// 处理工具调用
|
|
102
|
-
return await this._handleToolCalls(aiMessage);
|
|
103
|
-
} else {
|
|
104
|
-
// 普通回复
|
|
105
|
-
return await this._handleNormalResponse(aiMessage);
|
|
106
|
-
}
|
|
107
|
-
} catch (error) {
|
|
108
|
-
this.emit('error', {
|
|
109
|
-
error: error,
|
|
110
|
-
message: userMessage,
|
|
111
|
-
timestamp: new Date()
|
|
112
|
-
});
|
|
113
|
-
throw error;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* 处理工具调用(支持循环调用)
|
|
119
|
-
*/
|
|
120
|
-
async _handleToolCalls(aiMessage, maxIterations = 5) {
|
|
121
|
-
console.log('🔍 处理工具调用,aiMessage:', aiMessage);
|
|
122
|
-
|
|
123
|
-
let iteration = 0;
|
|
124
|
-
let currentMessage = aiMessage;
|
|
125
|
-
|
|
126
|
-
// 循环处理工具调用,直到没有工具调用或达到最大迭代次数
|
|
127
|
-
while (iteration < maxIterations) {
|
|
128
|
-
iteration++;
|
|
129
|
-
console.log(`🔄 工具调用迭代 ${iteration}/${maxIterations}`);
|
|
130
|
-
|
|
131
|
-
// 1. 添加助手消息(包含工具调用和思考内容)
|
|
132
|
-
this.messages.addAssistantMessage(currentMessage.content || '', {
|
|
133
|
-
tool_calls: currentMessage.tool_calls,
|
|
134
|
-
reasoning_content: currentMessage.reasoning_content || '' // ✅ 新增:保存思考内容
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
// 触发事件:AI请求工具调用
|
|
138
|
-
this.emit('tool-call-requested', {
|
|
139
|
-
tool_calls: currentMessage.tool_calls,
|
|
140
|
-
reasoning_content: currentMessage.reasoning_content, // ✅ 新增:包含思考内容
|
|
141
|
-
timestamp: new Date(),
|
|
142
|
-
iteration: iteration
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
// 2. 执行工具
|
|
146
|
-
const toolResults = await this.toolManager.executeToolCalls(currentMessage.tool_calls);
|
|
147
|
-
console.log('🔍 工具执行结果:', toolResults);
|
|
148
|
-
|
|
149
|
-
// 3. 添加工具结果消息
|
|
150
|
-
for (const result of toolResults) {
|
|
151
|
-
console.log('🔍 添加工具消息,result:', result);
|
|
152
|
-
this.messages.addToolMessage(
|
|
153
|
-
result.result || result.error || '',
|
|
154
|
-
result.tool_call_id
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// 4. 检查当前消息状态
|
|
159
|
-
console.log('🔍 当前所有消息:', this.messages.getMessages());
|
|
160
|
-
|
|
161
|
-
// 5. 再次发送请求,获取AI对工具结果的响应
|
|
162
|
-
const requestBody = this.requestBuilder.toJSON();
|
|
163
|
-
console.log('🔍 第', iteration, '次请求体:', requestBody);
|
|
164
|
-
|
|
165
|
-
const response = await this.apiClient.send(requestBody);
|
|
166
|
-
currentMessage = response.choices[0].message;
|
|
167
|
-
|
|
168
|
-
// 6. 检查AI是否还有新的工具调用请求
|
|
169
|
-
if (!currentMessage.tool_calls || currentMessage.tool_calls.length === 0) {
|
|
170
|
-
// 没有更多工具调用,结束循环
|
|
171
|
-
console.log('✅ 工具调用完成,AI给出最终回复');
|
|
172
|
-
break;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
console.log('🔄 AI请求了新的工具调用,继续处理...');
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// 7. 添加最终助手消息
|
|
179
|
-
this.messages.addAssistantMessage(currentMessage.content || '', {
|
|
180
|
-
reasoning_content: currentMessage.reasoning_content || '' // ✅ 新增:保存最终思考内容
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
// 触发事件:收到最终回复
|
|
184
|
-
this.emit('message', {
|
|
185
|
-
role: 'assistant',
|
|
186
|
-
content: currentMessage.content,
|
|
187
|
-
reasoning_content: currentMessage.reasoning_content, // ✅ 新增:包含思考内容
|
|
188
|
-
timestamp: new Date(),
|
|
189
|
-
response: { choices: [{ message: currentMessage }] },
|
|
190
|
-
toolIterations: iteration
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
return currentMessage.content;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* 处理普通回复
|
|
198
|
-
*/
|
|
199
|
-
async _handleNormalResponse(aiMessage) {
|
|
200
|
-
// 添加助手消息,处理空内容
|
|
201
|
-
this.messages.addAssistantMessage(aiMessage.content || '', {
|
|
202
|
-
reasoning_content: aiMessage.reasoning_content
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
// 触发事件:收到回复
|
|
206
|
-
this.emit('message', {
|
|
207
|
-
role: 'assistant',
|
|
208
|
-
content: aiMessage.content,
|
|
209
|
-
timestamp: new Date(),
|
|
210
|
-
response: { choices: [{ message: aiMessage }] }
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
return aiMessage.content;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* 流式发送消息(支持工具调用)
|
|
218
|
-
*/
|
|
219
|
-
async stream(userMessage, onProgress, onDone, options = {}) {
|
|
220
|
-
try {
|
|
221
|
-
// 触发事件:开始发送
|
|
222
|
-
this.emit('sending', {
|
|
223
|
-
role: 'user',
|
|
224
|
-
content: userMessage,
|
|
225
|
-
timestamp: new Date()
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
// 添加用户消息
|
|
229
|
-
this.messages.addUserMessage(userMessage);
|
|
230
|
-
|
|
231
|
-
// 构建请求体 - 关键:设置stream: true
|
|
232
|
-
const requestBuilder = new RequestBuilder(this.requestBuilder.model, this.messages, {
|
|
233
|
-
...this.requestBuilder.config,
|
|
234
|
-
stream: true // ✅ 必须设置为true!
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
const requestBody = requestBuilder.toJSON(
|
|
238
|
-
options.baseRounds,
|
|
239
|
-
options.cycleRounds
|
|
240
|
-
);
|
|
241
|
-
|
|
242
|
-
// 流式发送
|
|
243
|
-
const response = await this.apiClient.strSend(
|
|
244
|
-
requestBody,
|
|
245
|
-
(chunk) => {
|
|
246
|
-
// 流式进度回调
|
|
247
|
-
this.emit('stream-progress', chunk);
|
|
248
|
-
onProgress(chunk);
|
|
249
|
-
},
|
|
250
|
-
async (finalMessage) => {
|
|
251
|
-
// 流式完成回调
|
|
252
|
-
if (finalMessage.tool_calls && finalMessage.tool_calls.length > 0) {
|
|
253
|
-
// 处理流式中的工具调用
|
|
254
|
-
await this._handleStreamToolCalls(finalMessage, onProgress, onDone);
|
|
255
|
-
} else {
|
|
256
|
-
// 普通流式回复
|
|
257
|
-
this.messages.addAssistantMessage(finalMessage.content || '', {
|
|
258
|
-
reasoning_content: finalMessage.reasoning_content
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
this.emit('stream-done', { message: finalMessage });
|
|
262
|
-
onDone(finalMessage);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
);
|
|
266
|
-
|
|
267
|
-
return response;
|
|
268
|
-
} catch (error) {
|
|
269
|
-
this.emit('error', {
|
|
270
|
-
error: error,
|
|
271
|
-
message: userMessage,
|
|
272
|
-
timestamp: new Date()
|
|
273
|
-
});
|
|
274
|
-
throw error;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* 处理流式传输中的工具调用(支持循环调用)
|
|
280
|
-
*/
|
|
281
|
-
async _handleStreamToolCalls(aiMessage, onProgress, onDone, maxIterations = 5) {
|
|
282
|
-
let iteration = 0;
|
|
283
|
-
let currentMessage = aiMessage;
|
|
284
|
-
|
|
285
|
-
// 循环处理工具调用
|
|
286
|
-
while (iteration < maxIterations) {
|
|
287
|
-
iteration++;
|
|
288
|
-
|
|
289
|
-
// 1. 添加助手消息(包含工具调用和思考内容)
|
|
290
|
-
this.messages.addAssistantMessage(currentMessage.content || '', {
|
|
291
|
-
tool_calls: currentMessage.tool_calls,
|
|
292
|
-
reasoning_content: currentMessage.reasoning_content || '' // ✅ 新增:保存思考内容
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
// 触发事件:AI请求工具调用
|
|
296
|
-
this.emit('tool-call-requested', {
|
|
297
|
-
tool_calls: currentMessage.tool_calls,
|
|
298
|
-
reasoning_content: currentMessage.reasoning_content, // ✅ 新增:包含思考内容
|
|
299
|
-
timestamp: new Date(),
|
|
300
|
-
iteration: iteration
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
// 2. 执行工具
|
|
304
|
-
const toolResults = await this.toolManager.executeToolCalls(currentMessage.tool_calls);
|
|
305
|
-
|
|
306
|
-
// 3. 添加工具结果消息
|
|
307
|
-
for (const result of toolResults) {
|
|
308
|
-
this.messages.addToolMessage(result.result || result.error, result.tool_call_id);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// 4. 再次发送流式请求(包含工具结果)
|
|
312
|
-
const requestBody = this.requestBuilder.toJSON();
|
|
313
|
-
|
|
314
|
-
// 使用Promise包装流式请求,等待完成
|
|
315
|
-
await new Promise((resolve, reject) => {
|
|
316
|
-
this.apiClient.strSend(
|
|
317
|
-
requestBody,
|
|
318
|
-
(chunk) => {
|
|
319
|
-
this.emit('stream-progress', chunk);
|
|
320
|
-
onProgress(chunk);
|
|
321
|
-
},
|
|
322
|
-
(finalMessage) => {
|
|
323
|
-
currentMessage = finalMessage;
|
|
324
|
-
|
|
325
|
-
// 检查是否还有工具调用
|
|
326
|
-
if (!currentMessage.tool_calls || currentMessage.tool_calls.length === 0) {
|
|
327
|
-
// 没有更多工具调用,结束循环
|
|
328
|
-
resolve();
|
|
329
|
-
} else {
|
|
330
|
-
// 还有工具调用,继续循环
|
|
331
|
-
resolve();
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
).catch(reject);
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
// 如果没有工具调用了,跳出循环
|
|
338
|
-
if (!currentMessage.tool_calls || currentMessage.tool_calls.length === 0) {
|
|
339
|
-
break;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// 添加最终助手消息
|
|
344
|
-
this.messages.addAssistantMessage(currentMessage.content, {
|
|
345
|
-
reasoning_content: currentMessage.reasoning_content || '' // ✅ 新增:保存最终思考内容
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
this.emit('stream-done', {
|
|
349
|
-
message: currentMessage,
|
|
350
|
-
reasoning_content: currentMessage.reasoning_content, // ✅ 新增:包含思考内容
|
|
351
|
-
toolIterations: iteration
|
|
352
|
-
});
|
|
353
|
-
onDone(currentMessage);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* 撤回消息
|
|
358
|
-
*/
|
|
359
|
-
undo() {
|
|
360
|
-
const removed = this.messages.undoToAssistant();
|
|
361
|
-
if (removed.length > 0) {
|
|
362
|
-
this.emit('undo', {
|
|
363
|
-
removedMessages: removed,
|
|
364
|
-
timestamp: new Date()
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
return removed;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* 清空消息
|
|
372
|
-
*/
|
|
373
|
-
clear() {
|
|
374
|
-
const removed = this.messages.clearMessages();
|
|
375
|
-
this.emit('clear', {
|
|
376
|
-
removedMessages: removed,
|
|
377
|
-
timestamp: new Date()
|
|
378
|
-
});
|
|
379
|
-
return removed;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* 导出对话数据
|
|
384
|
-
*/
|
|
385
|
-
export() {
|
|
386
|
-
const data = this.messages.export();
|
|
387
|
-
this.emit('export', {
|
|
388
|
-
data: data,
|
|
389
|
-
timestamp: new Date()
|
|
390
|
-
});
|
|
391
|
-
return data;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* 导入对话数据
|
|
396
|
-
*/
|
|
397
|
-
import(data) {
|
|
398
|
-
this.messages.import(data);
|
|
399
|
-
this.emit('import', {
|
|
400
|
-
data: data,
|
|
401
|
-
timestamp: new Date()
|
|
402
|
-
});
|
|
403
|
-
return this;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// 导出 ChatService
|
|
408
|
-
export { ChatService };
|
|
409
|
-
|
|
410
|
-
// 导出默认对象
|
|
411
9
|
export default {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
ApiClient,
|
|
10
|
+
ChatService,
|
|
11
|
+
MessageStore,
|
|
415
12
|
EventEmitter,
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
ChatService
|
|
13
|
+
openaiAdapter,
|
|
14
|
+
toolCallingPlugin
|
|
419
15
|
};
|