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,16 @@
1
+ {
2
+ "sessionId": "test",
3
+ "messages": [
4
+ {
5
+ "role": "user",
6
+ "content": "hello"
7
+ }
8
+ ],
9
+ "variables": {},
10
+ "metadata": {
11
+ "createdAt": 1776011640311,
12
+ "lastActive": 1776011640311,
13
+ "messageCount": 0,
14
+ "compressionCount": 0
15
+ }
16
+ }
@@ -179,7 +179,8 @@
179
179
  "Bash(cd \"D:/Code/foliko\" && node test-python-ext.js 2>&1 | grep -v \"^\\\\[2m\")",
180
180
  "Bash(cd \"D:/Code/foliko\" && node -e \"require\\('./plugins/extension-executor-plugin'\\); console.log\\('OK'\\)\")",
181
181
  "Bash(cd D:/Code/foliko && timeout 8s node cli/bin/foliko.js chat 2>&1 || true)",
182
- "Bash(cd /d/Code/foliko-plugins/poster-plugin && node -e \"\nconst LayoutManager = require\\('./src/layout-manager'\\);\nconsole.log\\('LayoutManager loaded successfully'\\);\nconsole.log\\('Methods:', Object.getOwnPropertyNames\\(LayoutManager.prototype\\).join\\(', '\\)\\);\n\")"
182
+ "Bash(cd /d/Code/foliko-plugins/poster-plugin && node -e \"\nconst LayoutManager = require\\('./src/layout-manager'\\);\nconsole.log\\('LayoutManager loaded successfully'\\);\nconsole.log\\('Methods:', Object.getOwnPropertyNames\\(LayoutManager.prototype\\).join\\(', '\\)\\);\n\")",
183
+ "Bash(node test-ctx-push.js 2>&1 | head -50)"
183
184
  ]
184
185
  }
185
186
  }
@@ -140,24 +140,29 @@ class ChatUI {
140
140
  process.on('SIGINT', interruptHandler);
141
141
 
142
142
  let fullResponse = '';
143
+ let sessionScope = null;
143
144
 
144
145
  try {
145
146
  const renderState = { inThink: false, inCodeBlock: false };
146
147
  const runWithContext = this.agent.framework?.runWithContext.bind(this.agent.framework);
147
148
  const { sessionId } = this;
148
149
 
150
+ // 创建当前 session 的事件作用域,自动过滤其他 session 的事件
151
+ sessionScope = this.agent.createSessionScope(sessionId);
152
+
149
153
  if (this.stream) {
150
154
  // 流式模式
151
155
  console.log(colored('● ', GREEN));
152
156
 
153
157
  let lineBuffer = '';
154
158
  await runWithContext({ sessionId }, async () => {
155
- await this.agent.continue(message, sessionId, {
156
- onChunk: (chunk) => {
159
+ // 使用 sessionScope 监听事件,自动只接收当前 session 的事件
160
+ if (sessionScope) {
161
+ sessionScope.on('stream:chunk', (data) => {
162
+ const { chunk } = data;
157
163
  if (interrupted) return;
158
164
 
159
165
  if (chunk.type === 'text') {
160
- fullResponse += chunk.text;
161
166
  lineBuffer += chunk.text;
162
167
 
163
168
  while (lineBuffer.includes('\n')) {
@@ -173,25 +178,37 @@ class ChatUI {
173
178
  } else if (chunk.type === 'tool-call') {
174
179
  console.log(
175
180
  `\n${colored('[工具调用]', YELLOW)} ${chunk.toolName}`,
181
+ `args=`,
176
182
  JSON.stringify(chunk.input)
177
183
  );
178
184
  } else if (chunk.type === 'error') {
179
185
  console.error(`\n${colored('[错误]', RED)} ${chunk.error}`);
180
186
  }
181
- },
182
- onComplete: async (full, ctx) => {
183
- const response = cleanResponse(full);
184
- if (!response) {
185
- console.log(colored('● 继续下一步...', DIM));
186
- ctx.push('继续进行下一步', { sessionId });
187
+ });
188
+
189
+ sessionScope.on('message:complete', ({ sessionId, content }) => {
190
+ const message = '继续下一步';
191
+ if (!content) {
192
+ console.log(colored(`● ${message}...`, DIM));
193
+ this.agent.sendMessage(message, {
194
+ sessionId: sessionId,
195
+ priority: 1,
196
+ });
187
197
  }
188
- },
189
- onError: async (err) => {
190
- console.error(`\n${colored('[错误]', RED)} ${err.message}`);
191
- },
198
+ });
199
+ }
200
+
201
+ const result = await this.agent.sendMessage(message, {
202
+ sessionId: sessionId,
203
+ priority: 1,
192
204
  });
193
205
  });
194
206
 
207
+ // 清除 session scope 的监听器
208
+ if (sessionScope) {
209
+ sessionScope.removeAllListeners();
210
+ }
211
+
195
212
  if (lineBuffer.trim() && !interrupted) {
196
213
  console.log(renderLine(lineBuffer, renderState));
197
214
  }
@@ -218,10 +235,15 @@ class ChatUI {
218
235
  }
219
236
  }
220
237
  } catch (err) {
238
+ console.log(err);
221
239
  if (!interrupted) {
222
240
  console.error(`\n${colored('[错误]', RED)} ${err.message}\n`);
223
241
  }
224
242
  } finally {
243
+ // 确保清理 session scope 的监听器
244
+ if (sessionScope) {
245
+ sessionScope.removeAllListeners();
246
+ }
225
247
  process.removeListener('SIGINT', interruptHandler);
226
248
  }
227
249
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foliko",
3
- "version": "1.1.12",
3
+ "version": "1.1.13",
4
4
  "description": "简约的插件化 Agent 框架",
5
5
  "main": "src/index.js",
6
6
  "type": "commonjs",
@@ -354,7 +354,7 @@ class ExtensionExecutorPlugin extends Plugin {
354
354
  existingPrompt = existingPrompt.replace(extRegex, '').trim();
355
355
 
356
356
  // 添加新的 Extensions 部分
357
- agent.setSystemPrompt(existingPrompt + '\n\n' + extDesc);
357
+ //agent.setSystemPrompt(existingPrompt + '\n\n' + extDesc);
358
358
  }
359
359
 
360
360
  _buildExtensionsDescription() {
@@ -81,18 +81,18 @@ class PythonPluginLoader extends Plugin {
81
81
  this._loadPythonPlugins()
82
82
 
83
83
  // 监听 agent 创建事件,附加 Python 插件信息到系统提示词
84
- framework.on('agent:created', (agent) => {
85
- this._refreshAgentPythonPluginsPrompt(agent)
86
- })
84
+ // framework.on('agent:created', (agent) => {
85
+ // this._refreshAgentPythonPluginsPrompt(agent)
86
+ // })
87
87
 
88
88
  // 等待框架就绪后,刷新所有已有 agent 的 Python 插件提示词
89
- if (framework._ready) {
90
- this._refreshAllAgentsPythonPluginsPrompt(framework)
91
- } else {
92
- framework.once('framework:ready', () => {
93
- this._refreshAllAgentsPythonPluginsPrompt(framework)
94
- })
95
- }
89
+ // if (framework._ready) {
90
+ // this._refreshAllAgentsPythonPluginsPrompt(framework)
91
+ // } else {
92
+ // framework.once('framework:ready', () => {
93
+ // this._refreshAllAgentsPythonPluginsPrompt(framework)
94
+ // })
95
+ // }
96
96
 
97
97
  return this
98
98
  }
@@ -275,7 +275,7 @@ class PythonPluginLoader extends Plugin {
275
275
  if (!pyDesc) return
276
276
 
277
277
  // 将 Python 插件描述追加到系统提示词
278
- agent.setSystemPrompt(existingPrompt + '\n\n' + pyDesc)
278
+ //agent.setSystemPrompt(existingPrompt + '\n\n' + pyDesc)
279
279
  }
280
280
 
281
281
  /**
@@ -87,13 +87,18 @@ class SubAgentPlugin extends Plugin {
87
87
  }
88
88
 
89
89
  // 获取从父Agent继承的工具
90
- const parentTools = this._getParentTools(parentAgent)
90
+ // const parentTools = this._getParentTools(parentAgent)
91
91
 
92
92
  // 确定LLM配置
93
93
  const aiPlugin = this._framework.pluginManager.get('ai')
94
94
  const llmConfig = this.llmConfig || (aiPlugin ? aiPlugin.getConfig() : {})
95
-
96
-
95
+ const all_tools=['ext_call']
96
+ if(Array.isArray(this.tools)){
97
+ all_tools.push(...this.tools)
98
+ }else if(typeof this.tools==='string'){
99
+ const list=this.tools.split(',').map(a=>a.trim())
100
+ all_tools.push(...list)
101
+ }
97
102
  // 创建子Agent,使用完整的 md 文件内容作为系统提示词
98
103
  this._agent = this._framework.createSubAgent({
99
104
  name: this.name,
@@ -102,9 +107,10 @@ class SubAgentPlugin extends Plugin {
102
107
  provider: llmConfig.provider,
103
108
  apiKey: llmConfig.apiKey,
104
109
  baseURL: llmConfig.baseURL,
105
- tools: this.tools||{}, // 自定义工具
106
- parentTools: parentTools
110
+ tools:{}, // 自定义工具
111
+ parentTools: all_tools
107
112
  })
113
+
108
114
 
109
115
  // 注册从父Agent继承的工具
110
116
  // for (const tool of parentTools) {
@@ -157,19 +163,20 @@ class SubAgentPlugin extends Plugin {
157
163
  const toolMap = new Map(allTools.map(t => [t.name, t]))
158
164
 
159
165
  // 如果没有指定 parentTools,返回全部
160
- if (!this.parentTools || this.parentTools.length === 0) {
166
+ if (this.parentTools === undefined) {
161
167
  return allTools
162
168
  }
169
+ // 如果是空数组,明确返回空(不要任何工具)
170
+ if (this.parentTools.length === 0) {
171
+ return []
172
+ }
163
173
  // 过滤指定工具
164
174
  const filtered = []
165
175
  for (const toolName of this.parentTools) {
166
176
  const tool = toolMap.get(toolName)
167
177
  if (tool) {
168
178
  filtered.push(tool)
169
- }
170
- // else {
171
- // console.warn(`[SubAgent:${this.config.name}] Parent tool not found: ${toolName}`)
172
- // }
179
+ }
173
180
  }
174
181
 
175
182
  return filtered
@@ -257,12 +264,12 @@ class SubAgentPlugin extends Plugin {
257
264
  }
258
265
 
259
266
  // 注册到框架(供后续创建的 Agent 同步)
260
- // framework.registerTool(toolDef)
267
+ framework.registerTool(toolDef)
261
268
 
262
269
  // // 如果主 Agent 已存在,直接注册到它
263
- // if (framework._mainAgent) {
264
- // framework._mainAgent.registerTool(toolDef)
265
- // }
270
+ if (framework._mainAgent) {
271
+ framework._mainAgent.registerTool(toolDef)
272
+ }
266
273
 
267
274
  //console.log(`[SubAgent:${this.config.name}] Delegate tool registered`)
268
275
  }
@@ -458,10 +465,14 @@ class SubAgentManagerPlugin extends Plugin {
458
465
 
459
466
  try {
460
467
  const result = await plugin.chat(args.task)
468
+ if(!result.success){
469
+ throw new Error(result.error||result.message)
470
+ }
471
+
461
472
  return {
462
473
  success: true,
463
474
  agent: args.agentName,
464
- result: result.message || result,
475
+ result: result?.message || result?.content||result,
465
476
  success: result.success !== false
466
477
  }
467
478
  } catch (err) {
@@ -365,11 +365,12 @@ class WeixinPlugin extends Plugin {
365
365
  * 使用 SessionPlugin 统一管理会话历史
366
366
  */
367
367
  _getSessionAgent(userId) {
368
+ const sessionId=`weixin_${userId}`
368
369
  // 检查缓存
369
370
  if (this._sessionAgents.has(userId)) {
370
371
  const agent = this._sessionAgents.get(userId)
371
372
  // log.info(' Reusing cached session agent for userId:', userId)
372
- return { agent, sessionId: `weixin_${userId}` }
373
+ return { agent, sessionId }
373
374
  }
374
375
 
375
376
  // 创建新 agent - 和 CLI 一样使用 createAgent
@@ -379,19 +380,24 @@ class WeixinPlugin extends Plugin {
379
380
  sharedPrompt: `工作目录: {{WORK_DIR}}`,
380
381
  metadata: { WORK_DIR: process.cwd() }
381
382
  })
383
+
382
384
  this._sessionAgents.set(userId, agent)
383
385
  // log.info(' Created new session agent for userId:', userId)
384
386
 
385
387
  // 使用 SessionPlugin 管理会话历史
386
388
  if (this._sessionPlugin) {
387
- const sessionId = `weixin_${userId}`
388
389
  this._sessionPlugin.getOrCreateSession(sessionId, {
389
390
  metadata: { platform: 'weixin', userId }
390
391
  })
391
392
  }
392
-
393
+ const sessionScope = agent.createSessionScope(sessionId);
394
+ // sessionScope.on('stream:chunk', ({chunk}) => {
395
+ // if (chunk.type === 'text') {
396
+ // process.stdout.write(chunk.text);
397
+ // }
398
+ // });
393
399
  // log.info(` Session ready for user: ${userId}`)
394
- return { agent, sessionId: `weixin_${userId}` }
400
+ return { agent, sessionId }
395
401
  }
396
402
 
397
403
  /**
@@ -468,28 +474,21 @@ class WeixinPlugin extends Plugin {
468
474
 
469
475
  try {
470
476
  // 使用 continue 获取流式响应
471
- let fullResponse = '';
472
-
473
- await agent.continue(text, sessionId, {
474
- onChunk: (text, full) => {
475
- if (text) fullResponse += text;
476
- },
477
- onComplete: async (full, ctx) => {
478
- const response = cleanResponse(full);
479
- if (response) {
480
- await this._sendMessageBatch(originalMsg, userId, response, true)
481
- } else {
482
- // 响应为空,压入继续消息
483
- const msg=`继续进行下一步`
484
- await this._sendMessageBatch(originalMsg, userId, msg, true)
485
- ctx.push(msg, { sessionId });
486
- }
487
- },
488
- onError: async (err) => {
489
- log.error(' Media chat error:', err.message);
490
- await this._sendMessageBatch(originalMsg, userId, `发生错误:${err.message}`, true)
491
- }
477
+ const result = await agent.sendMessage(text, {
478
+ sessionId: sessionId,
479
+ priority: 1,
492
480
  });
481
+ const errors=result.chunks.filter(a=>a.type==='error').map(a=>a.error)
482
+ if(errors.length){
483
+ throw new Error(errors.join('\n'))
484
+ }
485
+ if(result.content){
486
+ await this._sendMessageBatch(originalMsg, userId, result.content, true)
487
+ }else{
488
+ const msg=`继续进行下一步`
489
+ await this._sendMessageBatch(originalMsg, userId, msg, true)
490
+ agent.sendMessage(msg,{sessionId,priority: 1})
491
+ }
493
492
  } catch (err) {
494
493
  log.error(' Media chat error:', err)
495
494
  await this._sendMessageBatch(originalMsg, userId, `发生错误:${err.message}`, true)
@@ -516,29 +515,21 @@ class WeixinPlugin extends Plugin {
516
515
  await new Promise((resolve) => setTimeout(resolve, 1000))
517
516
 
518
517
  try {
519
- // 使用 continue 获取流式响应
520
- let fullResponse = '';
521
-
522
- await agent.continue(text, sessionId, {
523
- onChunk: (text, full) => {
524
- if (text) fullResponse += text;
525
- },
526
- onComplete: async (full, ctx) => {
527
- const response = cleanResponse(full);
528
- if (response) {
529
- await this._sendMessageBatch(originalMsg, userId, response, true)
530
- } else {
531
- // 响应为空,压入继续消息
532
- const msg=`继续进行下一步`
533
- await this._sendMessageBatch(originalMsg, userId, msg, true)
534
- ctx.push(msg, { sessionId });
535
- }
536
- },
537
- onError: async (err) => {
538
- log.error(' Chat error:', err.message);
539
- await this._sendMessageBatch(originalMsg, userId, `发生错误:${err.message}`, true)
540
- }
518
+ const result = await agent.sendMessage(text, {
519
+ sessionId: sessionId,
520
+ priority: 1,
541
521
  });
522
+ const errors=result.chunks.filter(a=>a.type==='error').map(a=>a.error)
523
+ if(errors.length){
524
+ throw new Error(errors.join('\n'))
525
+ }
526
+ if(result.content){
527
+ await this._sendMessageBatch(originalMsg, userId, result.content, true)
528
+ }else{
529
+ const msg=`继续进行下一步`
530
+ await this._sendMessageBatch(originalMsg, userId, msg, true)
531
+ agent.sendMessage(msg,{sessionId,priority: 1})
532
+ }
542
533
 
543
534
  } catch (err) {
544
535
  log.error(' Chat error:', err.message)