my-ai-chat-framework 1.1.0 → 2.7.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.
@@ -1,126 +1,51 @@
1
- /**
2
- * 简单的事件发射器类
3
- * 实现观察者模式,允许对象监听和触发事件
4
- */
5
- class EventEmitter {
6
- constructor() {
7
- //存储事件和对应的回调数组
8
- //结构:
9
- // { 'event_name': [ callback1, callback2 ] }
10
- this.events = {}
11
- }
12
-
13
- /**
14
- * 监听事件
15
- * @param {string} eventName - 要注册的事件名称
16
- * @param {Function} callback - 事件触发时执行的回调函数
17
- */
18
- //实现一个监听事件的方法
19
- on(eventName, callback) {
20
- //1.如果没有事件数组,先创建
21
- if (!this.events[eventName]) {
22
- this.events[eventName] = []
23
- }
24
-
25
- //2.给数组添加(push)事件
26
- this.events[eventName].push(callback)
27
-
28
- //返回一个取消键听得函数(方便实用)
29
- return () => this.off(eventName, callback)
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
+ * 支持同步/异步事件,handler 返回 Promise 时自动 await
4
+ */
5
+ export class EventEmitter {
6
+ constructor() {
7
+ this._events = new Map();
8
+ }
9
+
10
+ on(event, handler) {
11
+ if (!this._events.has(event)) this._events.set(event, []);
12
+ this._events.get(event).push(handler);
13
+ return () => this.off(event, handler);
14
+ }
15
+
16
+ off(event, handler) {
17
+ if (!this._events.has(event)) return;
18
+ const handlers = this._events.get(event).filter(h => h !== handler);
19
+ if (handlers.length) this._events.set(event, handlers);
20
+ else this._events.delete(event);
21
+ }
22
+
23
+ /**
24
+ * 同步触发事件
25
+ */
26
+ emit(event, data) {
27
+ if (!this._events.has(event)) return;
28
+ for (const handler of this._events.get(event)) {
29
+ try {
30
+ handler(data);
31
+ } catch (err) {
32
+ console.error(`事件 ${event} 处理出错:`, err);
33
+ }
34
+ }
35
+ }
36
+
37
+ /**
38
+ * 异步触发事件,逐个 await handler
39
+ * handler 返回 Promise 时自动等待
40
+ */
41
+ async emitAsync(event, data) {
42
+ if (!this._events.has(event)) return;
43
+ for (const handler of this._events.get(event)) {
44
+ try {
45
+ await handler(data);
46
+ } catch (err) {
47
+ console.error(`事件 ${event} 处理出错:`, err);
48
+ }
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,112 @@
1
+ /**
2
+ * 消息存储 - 极简实现
3
+ * 每条消息格式:
4
+ * {
5
+ * id?: string,
6
+ * role: 'user'|'assistant'|'system'|'tool',
7
+ * content: string,
8
+ * images?: Array<string>, // 图片引用(URL / id),框架不存储图片数据
9
+ * _ephemeral?: boolean, // 临时消息:仅底部连续时参与请求,续写后转正
10
+ * _complete?: boolean, // 流式是否完成(false=未完成/中断)
11
+ * prefix?: boolean, // 前缀续写标记
12
+ * toolCalls?: Array,
13
+ * toolCallId?: string,
14
+ * timestamp?: number,
15
+ * metadata?: any
16
+ * }
17
+ */
18
+ export class MessageStore {
19
+ constructor() {
20
+ this._messages = [];
21
+ this._idCounter = 0;
22
+ }
23
+
24
+ add(message) {
25
+ const msg = {
26
+ id: message.id || `msg_${Date.now()}_${++this._idCounter}`,
27
+ timestamp: message.timestamp || Date.now(),
28
+ ...message
29
+ };
30
+ this._messages.push(msg);
31
+ return msg;
32
+ }
33
+
34
+ addUser(content, metadata = {}) {
35
+ return this.add({ role: 'user', content, metadata });
36
+ }
37
+
38
+ addAssistant(content, metadata = {}) {
39
+ return this.add({ role: 'assistant', content, metadata });
40
+ }
41
+
42
+ addSystem(content, metadata = {}) {
43
+ return this.add({ role: 'system', content, metadata });
44
+ }
45
+
46
+ addTool(content, toolCallId, metadata = {}) {
47
+ return this.add({ role: 'tool', content, toolCallId, metadata });
48
+ }
49
+
50
+ /**
51
+ * 快速添加一次性的、带续写标记的 assistant 消息
52
+ * 适用于思维链引导、临时注入等场景
53
+ * @param {string} content — 引导内容
54
+ * @param {Object} [options] — { reasoningContent, prefix }
55
+ * @returns {Object} 添加的消息
56
+ */
57
+ addOnceAssistant(content, options = {}) {
58
+ return this.add({
59
+ role: 'assistant',
60
+ content,
61
+ reasoningContent: options.reasoningContent,
62
+ prefix: options.prefix !== false, // 默认开启续写
63
+ _ephemeral: true
64
+ });
65
+ }
66
+
67
+ getLast() {
68
+ return this._messages[this._messages.length - 1] || null;
69
+ }
70
+
71
+ getAll() {
72
+ return [...this._messages];
73
+ }
74
+
75
+ clear() {
76
+ this._messages = [];
77
+ }
78
+
79
+ // 撤回最后一条助手消息及其后的所有消息(用于工具调用循环)
80
+ undoToLastAssistant() {
81
+ let lastAssistantIndex = -1;
82
+ for (let i = this._messages.length - 1; i >= 0; i--) {
83
+ if (this._messages[i].role === 'assistant') {
84
+ lastAssistantIndex = i;
85
+ break;
86
+ }
87
+ }
88
+ if (lastAssistantIndex >= 0) {
89
+ const removed = this._messages.splice(lastAssistantIndex + 1);
90
+ return removed;
91
+ }
92
+ return [];
93
+ }
94
+
95
+ /**
96
+ * 更新消息:按 id 查找并合并 changes,不新增消息
97
+ * @param {string} id — 消息 id
98
+ * @param {Object} changes — 要合并的字段
99
+ * @returns {Object|null} 更新后的消息,未找到返回 null
100
+ */
101
+ update(id, changes) {
102
+ for (const msg of this._messages) {
103
+ if (msg.id === id) {
104
+ Object.assign(msg, changes);
105
+ // 更新 timestamp 便于排查
106
+ msg.timestamp = changes.timestamp || Date.now();
107
+ return msg;
108
+ }
109
+ }
110
+ return null;
111
+ }
112
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * SystemPromptStore — 系统提示词存储
3
+ *
4
+ * 职责:管理多条 system prompt 的增删改查与开关
5
+ * 与 MessageStore 分离,因为 system prompt 是"AI 行为准则",不是对话事件
6
+ *
7
+ * 每条记录格式:
8
+ * {
9
+ * id: string,
10
+ * content: string,
11
+ * enabled: boolean,
12
+ * timestamp: number
13
+ * }
14
+ */
15
+
16
+ export class SystemPromptStore {
17
+ constructor() {
18
+ this._prompts = [];
19
+ this._idCounter = 0;
20
+ }
21
+
22
+ /**
23
+ * 添加一条 system prompt
24
+ * @param {string} content — 提示词内容
25
+ * @param {boolean} [enabled=true] — 是否启用
26
+ * @returns {Object} 添加的记录
27
+ */
28
+ add(content, enabled = true) {
29
+ if (!content || typeof content !== 'string' || !content.trim()) {
30
+ throw new Error('[SystemPromptStore] content 必须是非空字符串');
31
+ }
32
+ const record = {
33
+ id: `sys_${Date.now()}_${++this._idCounter}`,
34
+ content: content.trim(),
35
+ enabled: Boolean(enabled),
36
+ timestamp: Date.now()
37
+ };
38
+ this._prompts.push(record);
39
+ return record;
40
+ }
41
+
42
+ /**
43
+ * 删除指定索引的 system prompt
44
+ * @param {number} index
45
+ * @returns {Object} 被删除的记录
46
+ */
47
+ remove(index) {
48
+ if (index < 0 || index >= this._prompts.length) {
49
+ throw new Error(`[SystemPromptStore] 索引越界: ${index}`);
50
+ }
51
+ return this._prompts.splice(index, 1)[0];
52
+ }
53
+
54
+ /**
55
+ * 切换指定索引的启用/禁用状态
56
+ * @param {number} index
57
+ * @returns {boolean} 切换后的状态
58
+ */
59
+ toggle(index) {
60
+ if (index < 0 || index >= this._prompts.length) {
61
+ throw new Error(`[SystemPromptStore] 索引越界: ${index}`);
62
+ }
63
+ this._prompts[index].enabled = !this._prompts[index].enabled;
64
+ return this._prompts[index].enabled;
65
+ }
66
+
67
+ /**
68
+ * 更新指定索引的 content
69
+ * @param {number} index
70
+ * @param {string} content
71
+ */
72
+ update(index, content) {
73
+ if (index < 0 || index >= this._prompts.length) {
74
+ throw new Error(`[SystemPromptStore] 索引越界: ${index}`);
75
+ }
76
+ if (!content || typeof content !== 'string' || !content.trim()) {
77
+ throw new Error('[SystemPromptStore] content 必须是非空字符串');
78
+ }
79
+ this._prompts[index].content = content.trim();
80
+ this._prompts[index].timestamp = Date.now();
81
+ }
82
+
83
+ /**
84
+ * 清空并用一条 content 替换(便捷方法,常用于 config.system = '...')
85
+ * @param {string} content
86
+ */
87
+ set(content) {
88
+ this._prompts = [];
89
+ if (content && typeof content === 'string' && content.trim()) {
90
+ this.add(content, true);
91
+ }
92
+ }
93
+
94
+ /**
95
+ * 按 enabled 筛选后,转为适配器可用的格式
96
+ * @returns {Array<{role:'system', content:string}>}
97
+ */
98
+ getEnabled() {
99
+ return this._prompts
100
+ .filter(p => p.enabled)
101
+ .map(p => ({ role: 'system', content: p.content }));
102
+ }
103
+
104
+ /**
105
+ * 返回所有记录(含 enabled 状态,用于 UI 展示)
106
+ * @returns {Array}
107
+ */
108
+ getAll() {
109
+ return [...this._prompts];
110
+ }
111
+
112
+ /**
113
+ * 清空所有 system prompt
114
+ */
115
+ clear() {
116
+ this._prompts = [];
117
+ }
118
+ }