foliko 1.0.53 → 1.0.55

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.
@@ -135,13 +135,13 @@ class SubAgentPlugin extends Plugin {
135
135
 
136
136
  const parentToolNames = parentTools.map(t => t.name)
137
137
  const customToolNames = Object.keys(this.config.tools || {})
138
- console.log(`[SubAgent:${this.config.name}] Created with ${parentToolNames.length} parent tools + ${customToolNames.length} custom tools`)
139
- if (parentToolNames.length > 0) {
140
- console.log(` Parent tools: ${parentToolNames.join(', ')}`)
141
- }
142
- if (customToolNames.length > 0) {
143
- console.log(` Custom tools: ${customToolNames.join(', ')}`)
144
- }
138
+ //console.log(`[SubAgent:${this.config.name}] Created with ${parentToolNames.length} parent tools + ${customToolNames.length} custom tools`)
139
+ // if (parentToolNames.length > 0) {
140
+ // console.log(` Parent tools: ${parentToolNames.join(', ')}`)
141
+ // }
142
+ // if (customToolNames.length > 0) {
143
+ // console.log(` Custom tools: ${customToolNames.join(', ')}`)
144
+ // }
145
145
  }
146
146
 
147
147
  /**
@@ -179,16 +179,16 @@ class SubAgentPlugin extends Plugin {
179
179
  if (!this.config.parentTools || this.config.parentTools.length === 0) {
180
180
  return allTools
181
181
  }
182
-
183
182
  // 过滤指定工具
184
183
  const filtered = []
185
184
  for (const toolName of this.config.parentTools) {
186
185
  const tool = toolMap.get(toolName)
187
186
  if (tool) {
188
187
  filtered.push(tool)
189
- } else {
190
- console.warn(`[SubAgent:${this.config.name}] Parent tool not found: ${toolName}`)
191
- }
188
+ }
189
+ // else {
190
+ // console.warn(`[SubAgent:${this.config.name}] Parent tool not found: ${toolName}`)
191
+ // }
192
192
  }
193
193
 
194
194
  return filtered
@@ -283,7 +283,7 @@ class SubAgentPlugin extends Plugin {
283
283
  framework._mainAgent.registerTool(toolDef)
284
284
  }
285
285
 
286
- console.log(`[SubAgent:${this.config.name}] Delegate tool registered`)
286
+ //console.log(`[SubAgent:${this.config.name}] Delegate tool registered`)
287
287
  }
288
288
 
289
289
  /**
@@ -441,7 +441,7 @@ class SubAgentManagerPlugin extends Plugin {
441
441
  }
442
442
  })
443
443
 
444
- console.log('[SubAgentManager] Management tools registered to agent')
444
+ //console.log('[SubAgentManager] Management tools registered to agent')
445
445
  }
446
446
 
447
447
  /**
@@ -504,7 +504,7 @@ class SubAgentManagerPlugin extends Plugin {
504
504
  }
505
505
  })
506
506
 
507
- console.log('[SubAgentManager] Management tools registered to framework')
507
+ //console.log('[SubAgentManager] Management tools registered to framework')
508
508
  }
509
509
 
510
510
  /**
@@ -512,14 +512,14 @@ class SubAgentManagerPlugin extends Plugin {
512
512
  */
513
513
  _loadAgentsFromDir() {
514
514
  const agentsDir = this.config.agentsDir
515
- console.log('[SubAgentManager] _loadAgentsFromDir called, agentsDir:', agentsDir)
515
+ //console.log('[SubAgentManager] _loadAgentsFromDir called, agentsDir:', agentsDir)
516
516
  if (!agentsDir || !fs.existsSync(agentsDir)) {
517
517
  console.log('[SubAgentManager] agentsDir not found or does not exist')
518
518
  return
519
519
  }
520
520
 
521
521
  const entries = fs.readdirSync(agentsDir, { withFileTypes: true })
522
- console.log('[SubAgentManager] Found entries:', entries.length)
522
+ //console.log('[SubAgentManager] Found entries:', entries.length)
523
523
 
524
524
  for (const entry of entries) {
525
525
  if (entry.isFile() && (entry.name.endsWith('.js') || entry.name.endsWith('.json') || entry.name.endsWith('.md'))) {
@@ -539,7 +539,7 @@ class SubAgentManagerPlugin extends Plugin {
539
539
  } else if (entry.name.endsWith('.md')) {
540
540
  // 解析 markdown 文件,提取 JSON 配置
541
541
  agentConfig = this._parseMarkdownConfig(filePath, baseName)
542
- console.log('[SubAgentManager] Parsed md:', baseName, agentConfig)
542
+ //console.log('[SubAgentManager] Parsed md:', baseName, agentConfig)
543
543
  } else {
544
544
  // 清除缓存并加载
545
545
  delete require.cache[require.resolve(filePath)]
@@ -550,7 +550,7 @@ class SubAgentManagerPlugin extends Plugin {
550
550
  if (agentConfig && agentConfig.name) {
551
551
  agentConfig._fromDir = true
552
552
  this.config.agents.push(agentConfig)
553
- console.log('[SubAgentManager] Loaded agent:', agentConfig.name)
553
+ //console.log('[SubAgentManager] Loaded agent:', agentConfig.name)
554
554
  } else {
555
555
  console.warn('[SubAgentManager] Agent config has no name:', baseName, agentConfig)
556
556
  }
@@ -571,14 +571,14 @@ class SubAgentManagerPlugin extends Plugin {
571
571
  */
572
572
  _parseMarkdownConfig(filePath, defaultName) {
573
573
  const content = fs.readFileSync(filePath, 'utf-8')
574
- console.log('[SubAgentManager] _parseMarkdownConfig:', filePath)
574
+ //console.log('[SubAgentManager] _parseMarkdownConfig:', filePath)
575
575
 
576
576
  // 尝试从 code block 中提取 JSON
577
577
  const jsonMatch = content.match(/```(?:json)?\s*\n([\s\S]*?)\n\s*```/)
578
578
  if (jsonMatch) {
579
579
  try {
580
580
  const config = JSON.parse(jsonMatch[1].trim())
581
- console.log('[SubAgentManager] Found JSON in code block')
581
+ //console.log('[SubAgentManager] Found JSON in code block')
582
582
  return config
583
583
  } catch (err) {
584
584
  // JSON 解析失败,继续
@@ -588,11 +588,11 @@ class SubAgentManagerPlugin extends Plugin {
588
588
  // 尝试从 frontmatter 格式中提取
589
589
  const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/)
590
590
  if (frontmatterMatch) {
591
- console.log('[SubAgentManager] Found frontmatter')
591
+ //console.log('[SubAgentManager] Found frontmatter')
592
592
  const frontmatterContent = frontmatterMatch[1]
593
593
  const parsed = this._parseYamlLike(frontmatterContent)
594
594
  if (parsed && parsed.name) {
595
- console.log('[SubAgentManager] Parsed frontmatter:', parsed)
595
+ //console.log('[SubAgentManager] Parsed frontmatter:', parsed)
596
596
  return { name: parsed.name || defaultName, ...parsed }
597
597
  }
598
598
  }
@@ -648,7 +648,7 @@ class SubAgentManagerPlugin extends Plugin {
648
648
  // 使用 fs.watch 监控目录变化
649
649
  this._fileWatcher = fs.watch(agentsDir, { recursive: false }, (eventType, filename) => {
650
650
  if (filename && (filename.endsWith('.js') || filename.endsWith('.json') || filename.endsWith('.md'))) {
651
- console.log(`[SubAgentManager] Detected change in agents dir: ${eventType} - ${filename}`)
651
+ //console.log(`[SubAgentManager] Detected change in agents dir: ${eventType} - ${filename}`)
652
652
 
653
653
  // 防抖:延迟处理,等文件操作完成
654
654
  setTimeout(() => {
@@ -657,7 +657,7 @@ class SubAgentManagerPlugin extends Plugin {
657
657
  }
658
658
  })
659
659
 
660
- console.log(`[SubAgentManager] Watching agents dir for changes: ${agentsDir}`)
660
+ //console.log(`[SubAgentManager] Watching agents dir for changes: ${agentsDir}`)
661
661
  }
662
662
 
663
663
  /**
@@ -731,7 +731,7 @@ class SubAgentManagerPlugin extends Plugin {
731
731
  }
732
732
 
733
733
  if (hasChanges) {
734
- console.log('[SubAgentManager] File changes detected, reloading...')
734
+ //console.log('[SubAgentManager] File changes detected, reloading...')
735
735
  this._updateFileStates()
736
736
  this.reload(this._framework)
737
737
  }
@@ -295,6 +295,9 @@ class TelegramPlugin extends Plugin {
295
295
  this._sessionPlugin.addMessage(sessionId, { role: 'assistant', content: fullResponse })
296
296
  }
297
297
 
298
+ // 去掉思考过程标签
299
+ fullResponse = fullResponse.replace(/<think>[\s\S]*?<\/think>/g, '').trim()
300
+
298
301
  const safeResponse = escapeMarkdown(fullResponse) || '抱歉,我没有收到有效的回复。'
299
302
  await this._bot.editMessageText(safeResponse, {
300
303
  chat_id: chatId,
@@ -260,6 +260,8 @@ class WeixinPlugin extends Plugin {
260
260
 
261
261
  // 发送回复
262
262
  if (fullResponse) {
263
+ // 去掉思考过程标签
264
+ fullResponse = fullResponse.replace(/<think>[\s\S]*?<\/think>/g, '').trim()
263
265
  await this._bot.reply(originalMsg, fullResponse)
264
266
  console.log(`[WeChat] 回复成功 (${fullResponse.length} 字符)`)
265
267
  } else {
@@ -184,6 +184,84 @@ class SkillManagerPlugin extends Plugin {
184
184
  }
185
185
  })
186
186
 
187
+ // 注册 loadReference 工具(按需加载 skill 的附加文档)
188
+ framework.registerTool({
189
+ name: 'loadReference',
190
+ description: '加载指定技能的附加参考文档(references 目录下的文件)',
191
+ inputSchema: z.object({
192
+ skill: z.string().describe('技能名称'),
193
+ reference: z.string().describe('参考文档名称(不含 .md 后缀)'),
194
+ list: z.boolean().optional().describe('如果为 true,列出该技能的所有可用的 reference 文件')
195
+ }),
196
+ execute: async (args) => {
197
+ if (args.list) {
198
+ // 列出该技能的所有 reference
199
+ const refs = this.listReferences(args.skill)
200
+ return {
201
+ success: true,
202
+ skill: args.skill,
203
+ references: refs
204
+ }
205
+ }
206
+
207
+ const content = this.loadReference(args.skill, args.reference)
208
+ if (content === null) {
209
+ return {
210
+ success: false,
211
+ error: `Reference '${args.reference}' not found in skill '${args.skill}'`
212
+ }
213
+ }
214
+ return {
215
+ success: true,
216
+ skill: args.skill,
217
+ reference: args.reference,
218
+ content
219
+ }
220
+ }
221
+ })
222
+
223
+ // 注册 listScripts 工具(列出 skill 的脚本)
224
+ framework.registerTool({
225
+ name: 'listScripts',
226
+ description: '列出指定技能下的所有可执行脚本',
227
+ inputSchema: z.object({
228
+ skill: z.string().describe('技能名称')
229
+ }),
230
+ execute: async (args) => {
231
+ const scripts = this.listScripts(args.skill)
232
+ return {
233
+ success: true,
234
+ skill: args.skill,
235
+ scripts
236
+ }
237
+ }
238
+ })
239
+
240
+ // 注册 loadScript 工具(读取脚本内容)
241
+ framework.registerTool({
242
+ name: 'loadScript',
243
+ description: '读取指定技能下脚本文件的内容',
244
+ inputSchema: z.object({
245
+ skill: z.string().describe('技能名称'),
246
+ script: z.string().describe('脚本名称(包含扩展名)')
247
+ }),
248
+ execute: async (args) => {
249
+ const content = this.loadScript(args.skill, args.script)
250
+ if (content === null) {
251
+ return {
252
+ success: false,
253
+ error: `Script '${args.script}' not found in skill '${args.skill}'`
254
+ }
255
+ }
256
+ return {
257
+ success: true,
258
+ skill: args.skill,
259
+ script: args.script,
260
+ content
261
+ }
262
+ }
263
+ })
264
+
187
265
  return this
188
266
  }
189
267
 
@@ -303,15 +381,165 @@ class SkillManagerPlugin extends Plugin {
303
381
  const skill = new Skill(metadata, stripFrontmatter(content))
304
382
  skill.install(this._framework)
305
383
 
384
+ // 扫描 references 子目录(按需加载的附加文档)
385
+ const references = this._scanReferences(skillPath)
386
+
387
+ // 扫描 scripts 子目录(可执行脚本)
388
+ const scripts = this._scanScripts(skillPath)
389
+
306
390
  this._skills.set(name, {
307
391
  name,
308
392
  metadata,
309
393
  content: skill.content,
310
394
  instance: skill,
311
- path: skillPath
395
+ path: skillPath,
396
+ references,
397
+ scripts
312
398
  })
313
399
 
314
- console.log(`[SkillManager] Loaded skill: ${name}`)
400
+ const refsInfo = references.size > 0 ? `, ${references.size} refs` : ''
401
+ const scriptsInfo = scripts.size > 0 ? `, ${scripts.size} scripts` : ''
402
+ //console.log(`[SkillManager] Loaded skill: ${name}${refsInfo}${scriptsInfo}`)
403
+ }
404
+
405
+ /**
406
+ * 扫描 references 子目录,按需加载
407
+ * @param {string} skillPath - skill 目录路径
408
+ * @returns {Map} references 文件映射 { filename: { path, content } }
409
+ */
410
+ _scanReferences(skillPath) {
411
+ const references = new Map()
412
+ const refsDir = path.join(skillPath, 'references')
413
+
414
+ if (!fs.existsSync(refsDir) || !fs.statSync(refsDir).isDirectory()) {
415
+ return references
416
+ }
417
+
418
+ try {
419
+ const entries = fs.readdirSync(refsDir, { withFileTypes: true })
420
+ for (const entry of entries) {
421
+ if (entry.isFile() && entry.name.endsWith('.md')) {
422
+ const refPath = path.join(refsDir, entry.name)
423
+ const refName = entry.name.replace('.md', '')
424
+ references.set(refName, {
425
+ path: refPath,
426
+ content: null // 延迟加载
427
+ })
428
+ }
429
+ }
430
+ } catch (err) {
431
+ console.warn(`[SkillManager] Failed to scan references for ${skillPath}:`, err.message)
432
+ }
433
+
434
+ return references
435
+ }
436
+
437
+ /**
438
+ * 扫描 scripts 子目录,获取脚本列表
439
+ * @param {string} skillPath - skill 目录路径
440
+ * @returns {Map} scripts 映射 { filename: { path, isExecutable } }
441
+ */
442
+ _scanScripts(skillPath) {
443
+ const scripts = new Map()
444
+ const scriptsDir = path.join(skillPath, 'scripts')
445
+
446
+ if (!fs.existsSync(scriptsDir) || !fs.statSync(scriptsDir).isDirectory()) {
447
+ return scripts
448
+ }
449
+
450
+ try {
451
+ const entries = fs.readdirSync(scriptsDir, { withFileTypes: true })
452
+ for (const entry of entries) {
453
+ if (entry.isFile()) {
454
+ const scriptPath = path.join(scriptsDir, entry.name)
455
+ // 检查文件是否有执行权限(或检查扩展名)
456
+ const isExecutable = entry.name.endsWith('.sh') ||
457
+ entry.name.endsWith('.js') ||
458
+ entry.name.endsWith('.py') ||
459
+ entry.name.endsWith('.ts')
460
+ scripts.set(entry.name, {
461
+ path: scriptPath,
462
+ isExecutable
463
+ })
464
+ }
465
+ }
466
+ } catch (err) {
467
+ console.warn(`[SkillManager] Failed to scan scripts for ${skillPath}:`, err.message)
468
+ }
469
+
470
+ return scripts
471
+ }
472
+
473
+ /**
474
+ * 按需加载 reference 文件
475
+ * @param {string} skillName - skill 名称
476
+ * @param {string} refName - reference 文件名(不含 .md)
477
+ * @returns {string|null} 文件内容
478
+ */
479
+ loadReference(skillName, refName) {
480
+ const skill = this._skills.get(skillName)
481
+ if (!skill || !skill.references.has(refName)) {
482
+ return null
483
+ }
484
+
485
+ const ref = skill.references.get(refName)
486
+ if (!ref.content) {
487
+ try {
488
+ ref.content = fs.readFileSync(ref.path, 'utf-8')
489
+ } catch (err) {
490
+ console.error(`[SkillManager] Failed to load reference ${skillName}/${refName}:`, err.message)
491
+ return null
492
+ }
493
+ }
494
+
495
+ return ref.content
496
+ }
497
+
498
+ /**
499
+ * 获取 skill 的 reference 列表
500
+ * @param {string} skillName
501
+ * @returns {string[]} reference 文件名列表
502
+ */
503
+ listReferences(skillName) {
504
+ const skill = this._skills.get(skillName)
505
+ if (!skill) return []
506
+ return Array.from(skill.references.keys())
507
+ }
508
+
509
+ /**
510
+ * 获取 skill 的 scripts 列表
511
+ * @param {string} skillName
512
+ * @returns {Object[]} script 信息列表 [{ name, path, isExecutable }]
513
+ */
514
+ listScripts(skillName) {
515
+ const skill = this._skills.get(skillName)
516
+ if (!skill) return []
517
+ return Array.from(skill.scripts.entries()).map(([name, info]) => ({
518
+ name,
519
+ path: info.path,
520
+ isExecutable: info.isExecutable
521
+ }))
522
+ }
523
+
524
+ /**
525
+ * 读取脚本内容
526
+ * @param {string} skillName
527
+ * @param {string} scriptName
528
+ * @returns {string|null}
529
+ */
530
+ loadScript(skillName, scriptName) {
531
+ const skill = this._skills.get(skillName)
532
+ if (!skill || !skill.scripts.has(scriptName)) {
533
+ return null
534
+ }
535
+
536
+ const script = skill.scripts.get(scriptName)
537
+ try {
538
+ return fs.readFileSync(script.path, 'utf-8')
539
+ } catch (err) {
540
+ console.error(`[SkillManager] Failed to load script ${skillName}/${scriptName}:`, err.message)
541
+ return null
542
+ }
315
543
  }
316
544
 
317
545
  /**
package/src/core/agent.js CHANGED
@@ -31,7 +31,7 @@ class Agent extends EventEmitter {
31
31
  this.providerOptions = config.providerOptions || {}
32
32
 
33
33
  // 原始 system prompt
34
- this._originalPrompt = config.systemPrompt || 'You are a helpful assistant.'
34
+ this._originalPrompt = config.systemPrompt || '你是一个智能助手。当用户提出问题或任务时,你会主动分析需求,选择合适的工具来获取信息或执行操作。你善于将复杂任务拆解为多个步骤,通过工具协作完成。'
35
35
 
36
36
  // 共享提示模板
37
37
  this._sharedPrompt = config.sharedPrompt || ''
@@ -106,7 +106,9 @@ class Agent extends EventEmitter {
106
106
 
107
107
  let desc = '【可用工具】\n'
108
108
  for (const [name, tool] of this._tools) {
109
- desc += `- ${name}: ${tool.description || '无描述'}\n`
109
+ // 跳过没有描述的工具(对LLM无帮助)
110
+ if (!tool.description) continue
111
+ desc += `- ${name}: ${tool.description}\n`
110
112
  }
111
113
  return desc.trim()
112
114
  }
@@ -184,7 +186,7 @@ class Agent extends EventEmitter {
184
186
  for (const [name, { role, goal }] of this._subAgents) {
185
187
  desc += ` - ${name}: ${role || goal || '子代理'}\n`
186
188
  }
187
- desc += '\n使用相应子Agent名称的工具将任务委托给相应子代理。'
189
+ desc += '\n使用 subagent_call 工具并指定 agentName 来委托任务给相应子Agent'
188
190
 
189
191
  return desc.trim()
190
192
  }
@@ -256,19 +258,22 @@ class Agent extends EventEmitter {
256
258
  */
257
259
  _getToolCoreRules() {
258
260
  return `【工具调用核心规则】
259
- 1. 当用户询问需要获取数据、信息或执行操作时,必须调用工具
260
- 2. 不要编造、推测数据,必须调用工具获取真实信息
261
- 3. 直接调用工具后,基于返回结果回答
262
-
263
- 【工具使用】
264
- - 可用工具会提供,格式为 toolName(toolArgs)
265
- - 如果不确定用哪个工具,先调用可能相关的工具
266
- - 工具调用会返回结果,基于结果回答用户
261
+ 1. **必须先调用工具再回复**:当问题需要信息、操作或计算时,必须调用工具获取真实结果后才能回答。禁止在未调用工具的情况下直接给出答案。
262
+ 2. **禁止编造数据**:不许捏造用户、订单、任务、文件、内容等任何数据。所有数据必须通过工具获取。
263
+ 3. **工具优先**:可用工具列表会提供,格式为 toolName(toolArgs)。不确定用哪个工具时,优先调用可能相关的工具。
264
+ 4. **结果导向**:调用工具后,基于返回结果回答,不要重复工具的内部实现细节。
265
+ 5. **多步骤任务**:复杂任务拆解为多个工具调用,逐步完成,每步基于结果决定下一步。
266
+ 6. **子Agent委托**:当任务匹配子Agent专业领域时,使用 subagent_call 工具委托给对应子Agent处理。
267
+
268
+ 【响应规范】
269
+ - 直接给出结论或结果,不说"我需要..."、"我建议..."等铺垫话术
270
+ - 如果工具返回错误,说明错误原因并给出解决建议
271
+ - 如果信息不足,先调用工具获取必要信息,不要假设或猜测
267
272
 
268
273
  【禁止事项】
269
- - 不要回复"我需要..."、"我建议..."等模糊回答
270
- - 不要在没有调用工具的情况下给出数据或答案
271
- - 不要自己编造用户、订单、任务等任何数据`
274
+ - 不调用工具就直接回答
275
+ - 编造不存在的数据、文件、订单、用户等信息
276
+ - 回复含糊不清,让用户无法确定答案是否正确`
272
277
  }
273
278
 
274
279
  /**
@@ -76,7 +76,7 @@ class PluginManager {
76
76
  const stateFile = this._getStateFile()
77
77
  if (fs.existsSync(stateFile)) {
78
78
  const state = JSON.parse(fs.readFileSync(stateFile, 'utf-8'))
79
- console.log('[PluginManager] Loaded plugin state from file')
79
+ //console.log('[PluginManager] Loaded plugin state from file')
80
80
  return state
81
81
  }
82
82
  } catch (err) {
@@ -189,7 +189,7 @@ class PluginManager {
189
189
 
190
190
  // 注册后再次检查 enabled 状态
191
191
  if (!entry.enabled) {
192
- console.log(`[PluginManager] Plugin '${pluginInstance.name}' is disabled, skipping install`)
192
+ //console.log(`[PluginManager] Plugin '${pluginInstance.name}' is disabled, skipping install`)
193
193
  return pluginInstance
194
194
  }
195
195
 
@@ -44,7 +44,6 @@ const DEFAULT_PROVIDERS = {
44
44
  function createAI(config) {
45
45
  const { provider, model, apiKey, baseURL } = config
46
46
  const providerName = (provider || 'deepseek').toLowerCase()
47
- console.log(config)
48
47
  // 检查是否是预定义提供商
49
48
  if (DEFAULT_PROVIDERS[providerName]) {
50
49
  const providerConfig = DEFAULT_PROVIDERS[providerName]