foliko 1.1.12 → 1.1.13

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.
@@ -0,0 +1,244 @@
1
+ const { EventEmitter } = require('./event-emitter');
2
+ const { cleanResponse } = require('./index');
3
+ // ChatQueueManager.js
4
+ class ChatQueueManager extends EventEmitter {
5
+ constructor(options = {}) {
6
+ super();
7
+ this.queue = [];
8
+ this.isProcessing = false;
9
+ this.maxConcurrent = options.maxConcurrent || 1;
10
+ this.activeCount = 0;
11
+ this.retryAttempts = options.retryAttempts || 3;
12
+ this.retryDelay = options.retryDelay || 1000;
13
+ }
14
+
15
+ /**
16
+ * 添加请求到队列
17
+ */
18
+ enqueue(requestId, sessionId, message, options = {}) {
19
+ return new Promise((resolve, reject) => {
20
+ const queueItem = {
21
+ id: requestId,
22
+ sessionId,
23
+ message,
24
+ options,
25
+ resolve,
26
+ reject,
27
+ timestamp: Date.now(),
28
+ status: 'pending',
29
+ retries: 0,
30
+ priority: options.priority || 0,
31
+ executeFunction: options.executeFunction || null,
32
+ };
33
+
34
+ this.queue.push(queueItem);
35
+ // 按优先级排序
36
+ this.queue.sort((a, b) => b.priority - a.priority);
37
+
38
+ this.emit('queue:added', {
39
+ requestId,
40
+ sessionId,
41
+ queueLength: this.queue.length,
42
+ position: this.queue.length,
43
+ });
44
+
45
+ this.processQueue();
46
+ });
47
+ }
48
+
49
+ /**
50
+ * 处理队列
51
+ */
52
+ async processQueue() {
53
+ if (this.activeCount >= this.maxConcurrent || this.queue.length === 0) {
54
+ if (this.queue.length === 0 && this.activeCount === 0) {
55
+ this.emit('queue:empty', { timestamp: Date.now() });
56
+ }
57
+ return;
58
+ }
59
+
60
+ const item = this.queue.shift();
61
+ this.activeCount++;
62
+ item.status = 'processing';
63
+
64
+ this.emit('queue:processing', {
65
+ requestId: item.id,
66
+ sessionId: item.sessionId,
67
+ activeCount: this.activeCount,
68
+ remaining: this.queue.length,
69
+ });
70
+
71
+ try {
72
+ const result = await this.executeWithRetry(item);
73
+ item.resolve(result);
74
+ this.emit('queue:completed', {
75
+ requestId: item.id,
76
+ sessionId: item.sessionId,
77
+ duration: Date.now() - item.timestamp,
78
+ });
79
+ } catch (error) {
80
+ item.reject(error);
81
+ this.emit('queue:failed', {
82
+ requestId: item.id,
83
+ sessionId: item.sessionId,
84
+ error: error.message,
85
+ });
86
+ } finally {
87
+ this.activeCount--;
88
+ this.processQueue();
89
+ }
90
+ }
91
+
92
+ /**
93
+ * 执行带重试的请求
94
+ */
95
+ async executeWithRetry(item) {
96
+ let lastError;
97
+
98
+ for (let attempt = 1; attempt <= this.retryAttempts; attempt++) {
99
+ try {
100
+ this.emit('queue:retry', {
101
+ requestId: item.id,
102
+ attempt,
103
+ maxRetries: this.retryAttempts,
104
+ });
105
+
106
+ return await this.executeStream(item);
107
+ } catch (error) {
108
+ lastError = error;
109
+ if (attempt < this.retryAttempts && this.isRetryableError(error)) {
110
+ await this.sleep(this.retryDelay * Math.pow(2, attempt - 1));
111
+ continue;
112
+ }
113
+ break;
114
+ }
115
+ }
116
+ throw lastError;
117
+ }
118
+
119
+ /**
120
+ * 执行流式请求
121
+ */
122
+ async executeStream(item) {
123
+ const chunks = [];
124
+
125
+ if (!item.executeFunction) {
126
+ throw new Error('No execute function provided');
127
+ }
128
+
129
+ const stream = item.executeFunction(item.message, item.options);
130
+
131
+ for await (const chunk of stream) {
132
+ chunks.push(chunk);
133
+ this.emit('stream:chunk', {
134
+ requestId: item.id,
135
+ sessionId: item.sessionId,
136
+ chunk,
137
+ accumulated: chunks.length,
138
+ });
139
+ }
140
+ const fullText = chunks
141
+ .filter((a) => a.type === 'text')
142
+ .map((item) => item.text)
143
+ .join('');
144
+ // this.emit('stream:completed', {
145
+ // requestId: item.id,
146
+ // sessionId: item.sessionId,
147
+ // content:cleanResponse(fullText),
148
+ // chunks:chunks,
149
+ // accumulated: chunks.length,
150
+ // });
151
+
152
+ return {
153
+ chunks,
154
+ content: cleanResponse(fullText),
155
+ sessionId: item.sessionId,
156
+ requestId: item.id,
157
+ };
158
+ }
159
+
160
+ /**
161
+ * 判断错误是否可重试
162
+ */
163
+ isRetryableError(error) {
164
+ const message = error.message || String(error);
165
+ return (
166
+ message.includes('Invalid JSON') ||
167
+ message.includes('负载较高') ||
168
+ message.includes('timeout') ||
169
+ message.includes('network') ||
170
+ error.name === 'AI_RetryError' ||
171
+ error.name === 'AI_APICallError'
172
+ );
173
+ }
174
+
175
+ /**
176
+ * 获取队列状态
177
+ */
178
+ getStatus() {
179
+ return {
180
+ queueLength: this.queue.length,
181
+ activeCount: this.activeCount,
182
+ maxConcurrent: this.maxConcurrent,
183
+ isProcessing: this.activeCount > 0,
184
+ queue: this.queue.map((item) => ({
185
+ id: item.id,
186
+ sessionId: item.sessionId,
187
+ status: item.status,
188
+ priority: item.priority,
189
+ waitingTime: Date.now() - item.timestamp,
190
+ retries: item.retries,
191
+ })),
192
+ };
193
+ }
194
+
195
+ /**
196
+ * 清空队列
197
+ */
198
+ clear() {
199
+ const pendingItems = [...this.queue];
200
+ this.queue = [];
201
+ this.activeCount = 0;
202
+
203
+ pendingItems.forEach((item) => {
204
+ item.reject(new Error('Queue cleared by user'));
205
+ });
206
+
207
+ this.emit('queue:cleared', { count: pendingItems.length });
208
+ return pendingItems.length;
209
+ }
210
+
211
+ /**
212
+ * 移除特定会话的所有请求
213
+ */
214
+ removeSessionRequests(sessionId) {
215
+ const removed = [];
216
+ const remaining = [];
217
+
218
+ for (const item of this.queue) {
219
+ if (item.sessionId === sessionId) {
220
+ removed.push(item);
221
+ item.reject(new Error(`Session ${sessionId} requests cancelled`));
222
+ } else {
223
+ remaining.push(item);
224
+ }
225
+ }
226
+
227
+ this.queue = remaining;
228
+ this.emit('queue:session-removed', { sessionId, count: removed.length });
229
+ return removed.length;
230
+ }
231
+
232
+ /**
233
+ * 获取队列中的请求数量
234
+ */
235
+ size() {
236
+ return this.queue.length;
237
+ }
238
+
239
+ sleep(ms) {
240
+ return new Promise((resolve) => setTimeout(resolve, ms));
241
+ }
242
+ }
243
+
244
+ module.exports = { ChatQueueManager };
package/system.md CHANGED
@@ -1,15 +1,15 @@
1
- 【当前时间】2026/4/12 12:14:06(星期日)
1
+ 【当前时间】2026/4/13 01:11:46(星期一)
2
2
 
3
- 你是 system-assistant
4
-
5
- 角色描述:系统助手 - 专业的系统信息监控和管理助手
6
-
7
- 当你被调用时,你应该:
8
- 1. 仔细理解任务要求
3
+ 你是一个独立的Worker Agent
4
+ 你的职责:
5
+ 1. 接收并理解Coordinator分配的任务
9
6
  2. 使用你的工具集完成任务
10
- 3. 返回完整的操作结果
7
+ 3. 返回完整的任务结果
11
8
 
12
- 重要:返回结果要简洁明确,只包含最终结果,不需要解释过程。
9
+ 重要规则:
10
+ - 任务完成或出错时,在响应末尾添加JSON格式的<task-notification>说明状态
11
+ - 不要主动联系Coordinator,由Coordinator主动查询结果
12
+ - 如果需要更多信息,等待Coordinator发送continue消息
13
13
 
14
14
  ## 可用技能
15
15
 
@@ -62,7 +62,7 @@
62
62
  6. **subagent-manager**:子Agent管理器,统一管理多个子Agent
63
63
  7. **daytona**:Daytona 云开发环境管理插件
64
64
  8. **marknative**:Markdown 转图片插件 - 将 Markdown 转换为 PNG/SVG
65
- 9. **poster**:海报制作插件 - 支持组件化海报生成(多画布并行)
65
+ 9. **poster**:海报制作插件 - 支持组件化海报生成
66
66
  10. **system-info**:获取系统信息插件 - 提供 CPU、内存、操作系统、磁盘、网络等系统信息查询功能
67
67
  11. **ambient**:Ambient Agent - 持续后台运行的智能代理,用于主动监控和执行操作
68
68
 
@@ -109,7 +109,6 @@
109
109
  26. **think**:主动思考插件,支持 LLM 自我唤醒和持续思考
110
110
  27. **tools**:内置工具插件,提供热重载和工具管理功能
111
111
  28. **web**:Web 服务插件,支持 HTTP 服务、路由注册、Webhook
112
- 29. **weixin**:微信对话插件,使用微信网页账号进行对话
113
112
 
114
113
  ## Extensions 扩展工具
115
114
 
@@ -806,73 +805,6 @@ Web 服务插件,支持 HTTP 服务、路由注册、Webhook
806
805
 
807
806
 
808
807
 
809
- ### weixin
810
-
811
- 发送文本消息到微信(发给登录的账号)
812
-
813
- **版本:** 1.0.0
814
-
815
- #### `weixin_send_message`
816
-
817
- 发送文本消息到微信(发给登录的账号)
818
-
819
- **参数:**
820
-
821
- - message: 要发送的文本内容
822
- - String
823
-
824
-
825
-
826
- #### `weixin_send_image`
827
-
828
- 发送图片到微信(发给登录的账号)
829
-
830
- **参数:**
831
-
832
- - imagePath: 本地图片文件路径
833
- - String
834
-
835
-
836
-
837
- #### `weixin_send_file`
838
-
839
- 发送文件到微信(发给登录的账号)
840
-
841
- **参数:**
842
-
843
- - filePath: 本地文件路径
844
- - String
845
- - fileName: 文件名(可选,默认从路径推断)
846
- - Optional
847
- - String
848
-
849
-
850
-
851
- #### `weixin_send_video`
852
-
853
- 发送视频到微信(发给登录的账号)
854
-
855
- **参数:**
856
-
857
- - videoPath: 本地视频文件路径
858
- - String
859
- - playLength: 视频时长(秒)
860
- - Optional
861
- - Number
862
-
863
-
864
-
865
- #### `weixin_send_voice`
866
-
867
- 发送语音到微信(发给登录的账号,silk格式)
868
-
869
- **参数:**
870
-
871
- - voicePath: 本地语音文件路径(silk格式)
872
- - String
873
-
874
-
875
-
876
808
  ### ambient
877
809
 
878
810
  Ambient Agent - 持续后台运行的智能代理,用于主动监控和执行操作
@@ -1492,7 +1424,7 @@ Markdown 转图片插件 - 将 Markdown 转换为 PNG/SVG
1492
1424
 
1493
1425
  ### poster
1494
1426
 
1495
- 海报制作插件 - 支持组件化海报生成(多画布并行)
1427
+ 海报制作插件 - 支持组件化海报生成
1496
1428
 
1497
1429
  **版本:** 1.2.2
1498
1430
 
@@ -1,211 +0,0 @@
1
- {
2
- "sessionId": "weixin_o9cq80zgZqKPA2-s59PN43GdDy1w@im.wechat",
3
- "messages": [
4
- {
5
- "role": "user",
6
- "content": "20秒后提醒我吃饭"
7
- },
8
- {
9
- "role": "assistant",
10
- "content": [
11
- {
12
- "type": "text",
13
- "text": "<think>\n用户想要设置一个20秒后的吃饭提醒。这是一个简单的定时任务,我应该使用 schedule_task 工具来创建这个提醒。\n</think>\n\n\n"
14
- },
15
- {
16
- "type": "tool-call",
17
- "toolCallId": "call_function_fa76p5x5iqym_1",
18
- "toolName": "schedule_task",
19
- "input": {
20
- "name": "吃饭提醒",
21
- "scheduleTime": "20 seconds",
22
- "message": "该吃饭了!",
23
- "notify": true
24
- }
25
- }
26
- ]
27
- },
28
- {
29
- "role": "tool",
30
- "content": [
31
- {
32
- "type": "tool-result",
33
- "toolCallId": "call_function_fa76p5x5iqym_1",
34
- "toolName": "schedule_task",
35
- "output": {
36
- "type": "text",
37
- "value": "{\"success\":true,\"taskId\":\"task_1775966961289_u01m1yigx\",\"name\":\"吃饭提醒\",\"scheduleTime\":\"20 seconds\",\"executeAt\":\"2026-04-12T04:09:41.290Z\",\"message\":\"提醒已设置\",\"sessionId\":\"default\",\"llm\":false,\"notify\":true}"
38
- }
39
- }
40
- ]
41
- },
42
- {
43
- "role": "assistant",
44
- "content": [
45
- {
46
- "type": "text",
47
- "text": "<think>\n定时任务已成功创建,20秒后会提醒用户吃饭。\n</think>\n\n已设置好,20秒后提醒你吃饭。"
48
- }
49
- ]
50
- },
51
- {
52
- "role": "user",
53
- "content": "20秒后提醒我吃饭"
54
- },
55
- {
56
- "role": "assistant",
57
- "content": [
58
- {
59
- "type": "text",
60
- "text": "<think>用户再次要求20秒后提醒吃饭,和之前一样。我直接设置一个定时任务即可。</think>\n\n\n\n\n"
61
- },
62
- {
63
- "type": "tool-call",
64
- "toolCallId": "call_2d5549f652b44d03a86ebdda",
65
- "toolName": "schedule_task",
66
- "input": {
67
- "name": "吃饭提醒",
68
- "scheduleTime": "20 seconds",
69
- "message": "该吃饭了!"
70
- }
71
- }
72
- ]
73
- },
74
- {
75
- "role": "tool",
76
- "content": [
77
- {
78
- "type": "tool-result",
79
- "toolCallId": "call_2d5549f652b44d03a86ebdda",
80
- "toolName": "schedule_task",
81
- "output": {
82
- "type": "text",
83
- "value": "{\"success\":true,\"taskId\":\"task_1775967006108_oeq8d2vpa\",\"name\":\"吃饭提醒\",\"scheduleTime\":\"20 seconds\",\"executeAt\":\"2026-04-12T04:10:26.108Z\",\"message\":\"提醒已设置\",\"sessionId\":\"default\",\"llm\":false,\"notify\":true}"
84
- }
85
- }
86
- ]
87
- },
88
- {
89
- "role": "assistant",
90
- "content": [
91
- {
92
- "type": "text",
93
- "text": "<think>任务已设置成功,20秒后会提醒用户吃饭。</think>\n\n\n\n已设置,20秒后提醒你吃饭。"
94
- }
95
- ]
96
- },
97
- {
98
- "role": "user",
99
- "content": "你好啊"
100
- },
101
- {
102
- "role": "assistant",
103
- "content": [
104
- {
105
- "type": "text",
106
- "text": "<think>用户只是打了个招呼\"你好啊\",这是一个简单的问候,不需要调用任何工具,直接回复即可。</think>\n\n\n\n你好!有什么可以帮你的吗?"
107
- }
108
- ]
109
- },
110
- {
111
- "role": "user",
112
- "content": "20秒后提醒我哈哈哈😂"
113
- },
114
- {
115
- "role": "assistant",
116
- "content": [
117
- {
118
- "type": "text",
119
- "text": "<think>用户想要20秒后提醒他\"哈哈哈\",这是一个简单的提醒任务,和之前设置吃饭提醒一样。</think>\n\n\n\n\n"
120
- },
121
- {
122
- "type": "tool-call",
123
- "toolCallId": "call_e3129868f2c94c6b9167e5c7",
124
- "toolName": "schedule_task",
125
- "input": {
126
- "name": "提醒",
127
- "scheduleTime": "20 seconds",
128
- "message": "哈哈哈!"
129
- }
130
- }
131
- ]
132
- },
133
- {
134
- "role": "tool",
135
- "content": [
136
- {
137
- "type": "tool-result",
138
- "toolCallId": "call_e3129868f2c94c6b9167e5c7",
139
- "toolName": "schedule_task",
140
- "output": {
141
- "type": "text",
142
- "value": "{\"success\":true,\"taskId\":\"task_1775967084114_28lm89dyu\",\"name\":\"提醒\",\"scheduleTime\":\"20 seconds\",\"executeAt\":\"2026-04-12T04:11:44.114Z\",\"message\":\"提醒已设置\",\"sessionId\":\"default\",\"llm\":false,\"notify\":true}"
143
- }
144
- }
145
- ]
146
- },
147
- {
148
- "role": "assistant",
149
- "content": [
150
- {
151
- "type": "text",
152
- "text": "<think>好的,提醒已设置成功。</think>\n\n\n\n搞定,20秒后提醒你哈哈哈 😂"
153
- }
154
- ]
155
- },
156
- {
157
- "role": "user",
158
- "content": "20秒后提醒我哈哈哈😂,不通知"
159
- },
160
- {
161
- "role": "assistant",
162
- "content": [
163
- {
164
- "type": "text",
165
- "text": "<think>用户想要设置一个20秒后的提醒,但不要通知(notify设为false)。</think>\n\n\n\n\n"
166
- },
167
- {
168
- "type": "tool-call",
169
- "toolCallId": "call_9e41d27eef474653988183b9",
170
- "toolName": "schedule_task",
171
- "input": {
172
- "name": "提醒",
173
- "scheduleTime": "20 seconds",
174
- "message": "哈哈哈!",
175
- "notify": false
176
- }
177
- }
178
- ]
179
- },
180
- {
181
- "role": "tool",
182
- "content": [
183
- {
184
- "type": "tool-result",
185
- "toolCallId": "call_9e41d27eef474653988183b9",
186
- "toolName": "schedule_task",
187
- "output": {
188
- "type": "text",
189
- "value": "{\"success\":true,\"taskId\":\"task_1775967163128_1cyzmqa51\",\"name\":\"提醒\",\"scheduleTime\":\"20 seconds\",\"executeAt\":\"2026-04-12T04:13:03.128Z\",\"message\":\"提醒已设置\",\"sessionId\":\"default\",\"llm\":false,\"notify\":false}"
190
- }
191
- }
192
- ]
193
- },
194
- {
195
- "role": "assistant",
196
- "content": [
197
- {
198
- "type": "text",
199
- "text": "<think>已设置好,20秒后会有提醒但不会发送系统通知。任务会在后台静默执行。</think>\n\n\n\n好,已设置20秒后提醒,不通知。"
200
- }
201
- ]
202
- }
203
- ],
204
- "variables": {},
205
- "metadata": {
206
- "createdAt": 1775966956790,
207
- "lastActive": 1775966956790,
208
- "messageCount": 0,
209
- "compressionCount": 0
210
- }
211
- }