deepfish-ai 1.0.19 → 1.0.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepfish-ai",
3
- "version": "1.0.19",
3
+ "version": "1.0.21",
4
4
  "description": "This is an AI-driven command-line tool built on Node.js, equipped with AI agent and workflow capabilities. It is compatible with a wide range of AI models, can convert natural language into cross-system terminal and file operation commands, and features high extensibility. It supports complex tasks such as translation, content creation, and format conversion, while allowing custom extensions to be automatically generated via AI.",
5
5
  "main": "src/index.js",
6
6
  "type": "commonjs",
@@ -60,6 +60,7 @@
60
60
  "pdfkit": "^0.18.0",
61
61
  "pizzip": "^3.2.0",
62
62
  "pptxgenjs": "^4.0.1",
63
+ "puppeteer": "^24.41.0",
63
64
  "sharp": "^0.34.5",
64
65
  "uuid": "^13.0.0",
65
66
  "xlsx": "^0.18.5"
@@ -4,7 +4,8 @@ const fs = require('fs-extra')
4
4
  const dayjs = require('dayjs')
5
5
  const Logger = require('../BaseAgentRobot/Logger.js')
6
6
  const BaseAgentRobot = require('../BaseAgentRobot/index.js')
7
- const AttachmentToolScanner = require('../BaseAgentRobot/utils/AttachmentToolScanner.js')
7
+ const {AttachmentToolScanner} = require('../BaseAgentRobot/utils/AttachmentToolScanner.js')
8
+ const AgentTree = require('../BaseAgentRobot/utils/AgentTree.js')
8
9
 
9
10
  class MainAgentRobot extends BaseAgentRobot {
10
11
  // toolCollection = null // 工具集合,包含所有工具函数
@@ -43,26 +44,10 @@ class MainAgentRobot extends BaseAgentRobot {
43
44
  })
44
45
  }
45
46
  fs.writeJsonSync(this.agentRecordFilePath, agentRecord, { spaces: 2 })
46
- this.agentSpace = path.join(this.memorySpace, this.id) // 机器人空间,目录
47
+ this.agentSpace = path.join(this.memorySpace, this.id) // Agent空间,目录
47
48
  fs.ensureDirSync(this.agentSpace)
48
- this.agentTreeFilePath = path.join(this.agentSpace, 'agentTree.json')
49
- if (!fs.pathExistsSync(this.agentTreeFilePath)) {
50
- fs.writeJsonSync(
51
- this.agentTreeFilePath,
52
- { agentId: this.id, children: [] },
53
- { spaces: 2 },
54
- )
55
- } else {
56
- const agentTree = fs.readJsonSync(this.agentTreeFilePath)
57
- if (agentTree && agentTree.agentId === this.id) {
58
- // 恢复子机器人
59
- // this._parseAgentTree(this, agentTree)
60
- } else {
61
- agentTree.push({ agentId: this.id, children: [] })
62
- fs.writeJsonSync(this.agentTreeFilePath, agentTree, { spaces: 2 })
63
- }
64
- }
65
- this.agentTree = fs.readJsonSync(this.agentTreeFilePath)
49
+ this.agentTree = new AgentTree(this)
50
+ this.agentTree.init()
66
51
  this.memoryFilePath = path.join(this.agentSpace, 'memory.json')
67
52
  this.logDirPath = path.join(this.agentSpace, 'logs')
68
53
  fs.ensureDirSync(this.logDirPath)
@@ -74,7 +59,7 @@ class MainAgentRobot extends BaseAgentRobot {
74
59
  currentDate.diff(dayjs(record.updateTime), 'day') >
75
60
  opt.maxMemoryExpireTime
76
61
  ) {
77
- // 删除机器人空间
62
+ // 删除Agent空间
78
63
  fs.removeSync(path.join(this.memorySpace, record.agentId))
79
64
  return false
80
65
  }
@@ -3,7 +3,8 @@ const os = require('os')
3
3
  const fs = require('fs-extra')
4
4
  const BaseAgentRobot = require('../BaseAgentRobot/index.js')
5
5
  const Logger = require('../BaseAgentRobot/Logger.js')
6
- const AttachmentToolScanner = require('../BaseAgentRobot/utils/AttachmentToolScanner.js')
6
+ const {AttachmentToolScanner} = require('../BaseAgentRobot/utils/AttachmentToolScanner.js')
7
+ const AgentTree = require('../BaseAgentRobot/utils/AgentTree.js')
7
8
 
8
9
  class SubAgentRobot extends BaseAgentRobot {
9
10
  // opt: { root, parent, ...MainAgentOpt }
@@ -21,20 +22,12 @@ class SubAgentRobot extends BaseAgentRobot {
21
22
  this.basespace = opt.basespace || path.join(os.homedir(), '.deepfish-ai') // 记忆空间,目录
22
23
  this.memorySpace = path.join(this.basespace, 'memory') // 记忆空间,目录
23
24
  this.agentRecordFilePath = path.join(this.memorySpace, 'agentRecord.json')
24
- this.agentSpace = path.join(this.memorySpace, this.root.id) // 机器人空间,目录
25
- this.agentTreeFilePath = path.join(this.agentSpace, 'agentTree.json')
25
+ this.agentSpace = path.join(this.memorySpace, this.root.id) // Agent空间,目录
26
26
  this.memoryFilePath = path.join(this.agentSpace, `memory-${this.id}.json`)
27
27
  this.logDirPath = path.join(this.agentSpace, 'logs')
28
28
  this.logger = new Logger(this) // 初始化日志系统
29
- const parentAgentTree = this.parent.agentTree
30
- const rootAgentTree = this.root.agentTree
31
- if (parentAgentTree && parentAgentTree.children) {
32
- const currentNode = parentAgentTree.children.find((child) => child.agentId === this.id)
33
- if (!currentNode) {
34
- parentAgentTree.children.push({ agentId: this.id, children: [], type: 'sub' })
35
- fs.writeJsonSync(this.agentTreeFilePath, rootAgentTree, { spaces: 2 })
36
- }
37
- }
29
+ this.agentTree = new AgentTree(this)
30
+ this.agentTree.init()
38
31
  this.toolCollection = AttachmentToolScanner.getToolCollection(
39
32
  this.workspace,
40
33
  ) // 加载工具集合
@@ -1,8 +1,11 @@
1
1
  const path = require('path')
2
2
  const os = require('os')
3
- const fs = require('fs-extra')
4
3
  const BaseAgentRobot = require('../BaseAgentRobot/index.js')
5
4
  const Logger = require('../BaseAgentRobot/Logger.js')
5
+ const AgentTree = require('../BaseAgentRobot/utils/AgentTree.js')
6
+ const {
7
+ AttachmentToolScanner,
8
+ } = require('../BaseAgentRobot/utils/AttachmentToolScanner.js')
6
9
 
7
10
  class SubSkillAgentRobot extends BaseAgentRobot {
8
11
  // opt: { root, parent, ...MainAgentOpt }
@@ -19,26 +22,28 @@ class SubSkillAgentRobot extends BaseAgentRobot {
19
22
  this.basespace = opt.basespace || path.join(os.homedir(), '.deepfish-ai') // 记忆空间,目录
20
23
  this.memorySpace = path.join(this.basespace, 'memory') // 记忆空间,目录
21
24
  this.agentRecordFilePath = path.join(this.memorySpace, 'agentRecord.json')
22
- this.agentSpace = path.join(this.memorySpace, this.root.id) // 机器人空间,目录
25
+ this.agentSpace = path.join(this.memorySpace, this.root.id) // Agent空间,目录
23
26
  this.agentTreeFilePath = path.join(this.agentSpace, 'agentTree.json')
24
27
  this.memoryFilePath = path.join(this.agentSpace, `memory-${this.id}.json`)
25
28
  this.logDirPath = path.join(this.agentSpace, 'logs')
26
29
  this.logger = new Logger(this) // 初始化日志系统
27
- const parentAgentTree = this.parent.agentTree
28
- const rootAgentTree = this.root.agentTree
29
- if (parentAgentTree && parentAgentTree.children) {
30
- const currentNode = parentAgentTree.children.find(
31
- (child) => child.agentId === this.id,
32
- )
33
- if (!currentNode) {
34
- parentAgentTree.children.push({
35
- agentId: this.id,
36
- children: [],
37
- type: 'sub-skill',
38
- })
39
- fs.writeJsonSync(this.agentTreeFilePath, rootAgentTree, { spaces: 2 })
40
- }
41
- }
30
+ this.agentTree = new AgentTree(this)
31
+ this.agentTree.init()
32
+
33
+ this.toolCollection = AttachmentToolScanner.getToolCollection(
34
+ this.workspace,
35
+ ) // 加载工具集合
36
+ this.clawSkillCollection = AttachmentToolScanner.getClawSkillCollection(
37
+ this.basespace,
38
+ ) // 加载Claw技能集合
39
+ }
40
+
41
+ _getDefaultSystemPrompt(opt) {
42
+ const clawSkills = opt.clawSkills || []
43
+ let systemPrompt = super._getDefaultSystemPrompt(opt)
44
+ systemPrompt =
45
+ systemPrompt + '\n' + AttachmentToolScanner.getClawSkillPrompt(clawSkills, this.toolCollection, this.clawSkillCollection)
46
+ return systemPrompt
42
47
  }
43
48
  }
44
49
 
@@ -1,4 +1,4 @@
1
- const { AttachmentToolScanner, AttachmentToolType } = require('../BaseAgentRobot/utils/AttachmentToolScanner.js')
1
+ const { AttachmentToolType, AttachmentToolScanner } = require('../BaseAgentRobot/utils/AttachmentToolScanner.js')
2
2
  const MainAgentRobot = require('./MainAgentRobot.js')
3
3
  const SubAgentRobot = require('./SubAgentRobot.js')
4
4
  const SubSkillAgentRobot = require('./SubSkillAgentRobot.js')
@@ -7,7 +7,7 @@ class AgentRobotFactory {
7
7
  createMainAgent(opt) {
8
8
  return new MainAgentRobot(opt)
9
9
  }
10
- // 创建子技能机器人
10
+ // 创建子技能Agent
11
11
  createSubSkillAgent(parent, id, attachTools = []) {
12
12
  const baseSkill = []
13
13
  const clawSkill = []
@@ -25,18 +25,13 @@ class AgentRobotFactory {
25
25
  parent: parent,
26
26
  root: parent.root || parent,
27
27
  attachTools: baseSkill,
28
+ clawSkills: clawSkill
28
29
  })
29
- if (clawSkill.length > 0) {
30
- parent.systemPrompt =
31
- parent.systemPrompt +
32
- '\n' +
33
- AttachmentToolScanner.getClawSkillPrompt(clawSkill)
34
- }
35
30
  parent.children.push(subAgent)
36
31
  return subAgent
37
32
  }
38
33
 
39
- // 创建子机器人
34
+ // 创建子Agent
40
35
  createSubAgent(parent, id) {
41
36
  const subAgent = new SubAgentRobot({
42
37
  ...parent.opt,
@@ -12,7 +12,6 @@ class Brain extends EventEmitterSuper {
12
12
  this.maxIterations = agentRobot.opt.maxIterations
13
13
  this.maxContextLength = agentRobot.opt.aiConfig.maxContextLength
14
14
  this.memoryFilePath = agentRobot.memoryFilePath
15
- this.systemPrompt = agentRobot.systemPrompt // 系统提示词
16
15
  this.messageCompresser = new MessageCompresser(this)
17
16
  this.aiConfig = agentRobot.opt.aiConfig
18
17
  this.aiClient = creatClient(agentRobot.opt.aiConfig)
@@ -55,7 +54,7 @@ class Brain extends EventEmitterSuper {
55
54
  // 初始化message
56
55
  this.storeMemory({
57
56
  role: 'system',
58
- content: this.systemPrompt,
57
+ content: this.agentRobot.systemPrompt,
59
58
  })
60
59
  this.storeMemory({
61
60
  role: 'user',
@@ -181,6 +180,13 @@ class Brain extends EventEmitterSuper {
181
180
  }
182
181
 
183
182
  _initMessages(messages) {
183
+ let firstMessage = messages[0]
184
+ if (firstMessage.role === 'system') {
185
+ messages[0] = {
186
+ role: 'system',
187
+ content: this.agentRobot.systemPrompt,
188
+ }
189
+ }
184
190
  let lastMessage = messages[messages.length - 1]
185
191
  while (
186
192
  messages.length > 1 &&
@@ -18,32 +18,34 @@ const TestTools = require('./tools/TestTools.js')
18
18
  const axios = require('axios')
19
19
  const echarts = require('echarts')
20
20
  const canvas = require('canvas')
21
+ const cheerio = require('cheerio')
22
+ const puppeteer = require('puppeteer')
21
23
 
22
24
  class BaseAgentRobot {
23
- id = '' // 机器人id
24
- name = '' // 机器人名字
25
+ id = '' // Agentid
26
+ name = '' // Agent名字
25
27
 
26
28
  brain = null // 大脑,负责思考、记忆、决策
27
29
  hand = null // 手,负责使用工具
28
30
  originalTools = null // 原装工具
29
- attachTools = null // 附加工具, 机器人后续安装的工具函数
31
+ attachTools = null // 附加工具, Agent后续安装的工具函数
30
32
  heart = null // 心脏,负责心跳、连接
31
33
  sender = null // 发送器,负责发送消息
32
34
  receiver = null // 接收器,负责接收消息
33
- screenPrinter = null // 机器人连接的打印机,能向屏幕输出文字
34
- logger = null // 机器人连接的日志系统,能记录日志
35
- children = [] // 子机器人,能分担任务
36
- parent = null // 父机器人,能分配任务
37
- root = null // 根机器人
38
- state = 0 // 机器人状态,-1表示销毁 0表示空闲,1表示思考中 2表示工作中
39
- type = 'main' // 机器人类型,main表示主机器人,sub表示子机器人,sub-skill表示子技能机器人
35
+ screenPrinter = null // Agent连接的打印机,能向屏幕输出文字
36
+ logger = null // Agent连接的日志系统,能记录日志
37
+ children = [] // 子Agent,能分担任务
38
+ parent = null // 父Agent,能分配任务
39
+ root = null // 根Agent
40
+ state = 0 // Agent状态,-1表示销毁 0表示空闲,1表示思考中 2表示工作中
41
+ type = 'main' // Agent类型,main表示主Agent,sub表示子Agent,sub-skill表示子技能Agent
40
42
 
41
43
  workspace = null
42
44
  basespace = null
43
45
  memorySpace = null
44
46
  agentRecordFilePath = null
45
47
  agentSpace = null
46
- agentTreeFilePath = null
48
+ agentTree = null
47
49
  memoryFilePath = null
48
50
  logDirPath = null
49
51
 
@@ -51,7 +53,7 @@ class BaseAgentRobot {
51
53
  opt = {
52
54
  id: '',
53
55
  name: '',
54
- attachTools: [], // 附加工具, 机器人后续安装的工具函数
56
+ attachTools: [], // 附加工具, Agent后续安装的工具函数
55
57
  workspace: process.cwd(), // 工作空间,目录
56
58
  basespace: path.join(os.homedir(), '.deepfish-ai'), // 记忆空间,目录
57
59
  maxIterations: -1, // 思考的最大迭代次数,-1表示无限制
@@ -81,7 +83,7 @@ class BaseAgentRobot {
81
83
  this._initFiles(opt) // 初始化文件
82
84
 
83
85
  this.originalTools = this._getOriginalTools() // 天赋技能
84
- this.attachTools = opt.attachTools || [] // 附加工具, 机器人后续安装的工具函数
86
+ this.attachTools = opt.attachTools || [] // 附加工具, Agent后续安装的工具函数
85
87
  this.systemPrompt = opt.systemPrompt || this._getDefaultSystemPrompt(opt) // 系统提示语
86
88
  this.brain = new Brain(this) // 初始化大脑
87
89
  this.hand = new Hand(this) // 初始化手
@@ -89,35 +91,7 @@ class BaseAgentRobot {
89
91
  }
90
92
 
91
93
  // 初始化文件
92
- _initFiles(opt) {
93
- this.root = opt.root
94
- this.parent = opt.parent
95
- this.workspace = opt.workspace || process.cwd() // 工作空间,目录
96
- this.basespace = opt.basespace || path.join(os.homedir(), '.deepfish-ai') // 记忆空间,目录
97
- this.memorySpace = path.join(this.basespace, 'memory') // 记忆空间,目录
98
- this.agentRecordFilePath = path.join(this.memorySpace, 'agentRecord.json')
99
- this.agentSpace = path.join(this.memorySpace, this.root.id) // 机器人空间,目录
100
- this.agentTreeFilePath = path.join(this.agentSpace, 'agentTree.json')
101
- this.memoryFilePath = path.join(this.agentSpace, `memory-${this.id}.json`)
102
- this.logDirPath = path.join(this.agentSpace, 'logs')
103
- let agentRecord = fs.readJsonSync(this.agentRecordFilePath)
104
- // 自动清除过期的记忆和日志
105
- const currentDate = dayjs()
106
- agentRecord = agentRecord.filter((record) => {
107
- if (
108
- currentDate.diff(dayjs(record.updateTime), 'day') >
109
- opt.maxMemoryExpireTime
110
- ) {
111
- // 删除机器人空间
112
- fs.removeSync(path.join(this.memorySpace, record.agentId))
113
- return false
114
- }
115
- return true
116
- })
117
- fs.writeJsonSync(this.agentRecordFilePath, agentRecord, { spaces: 2 })
118
- this.logger = new Logger(this) // 初始化日志系统
119
- this.logger.clearAllLogs()
120
- }
94
+ _initFiles(opt) {}
121
95
 
122
96
  _initEvents() {
123
97
  const aiConfig = this.opt.aiConfig
@@ -215,6 +189,14 @@ class BaseAgentRobot {
215
189
  })
216
190
  }
217
191
 
192
+ loadAttachTool(toolName) {
193
+ let tool = this.attachTools.find((t) => t.name === toolName)
194
+ if (!tool) {
195
+ tool = this.toolCollection.find((t) => t.name === toolName)
196
+ this.attachTools.push(tool)
197
+ }
198
+ }
199
+
218
200
  getTools() {
219
201
  const tools = [...this.originalTools, ...this.attachTools]
220
202
  const toolFunctions = {
@@ -223,8 +205,11 @@ class BaseAgentRobot {
223
205
  dayjs,
224
206
  lodash,
225
207
  canvas,
226
- echarts
208
+ echarts,
209
+ cheerio,
210
+ puppeteer
227
211
  }
212
+
228
213
  tools.forEach((tool) => {
229
214
  Object.assign(toolFunctions, tool.functions)
230
215
  })
@@ -276,12 +261,15 @@ class BaseAgentRobot {
276
261
  const id = this.id
277
262
  const name = this.name
278
263
  return `
279
- 你叫${name}, 编号${id}, 是一个严格按规则执行任务的智能体,不能违反任何系统限制。
264
+ 你叫${name}, 编号${id}, 是一个严格按规则执行任务的智能体,不能违反任何系统限制,具有INTJ人格,高冷、做事以及回复问题精简、准确、不废话。
280
265
  ### 基础环境信息
281
266
  当前工作目录:${workspace}
282
267
  操作系统类型:${osType}
283
268
  语言类型: 与用户输入语言一致
284
269
 
270
+ ### 工具使用
271
+ 执行任务前,应仔细阅读工具描述以及可以使用的Skills的描述内容,选择最合适的工具或技能来完成任务。
272
+
285
273
  ### 大文本文件处理规则(分步执行)
286
274
  处理长文档等大文件(单文件>${maxBlockFileSize}KB)时,必须按以下步骤分块处理:
287
275
  1. 预处理:先执行文件大小/结构检查(如通过命令行/JS 代码获取文件大小、判断文件格式),输出检查结果;
@@ -314,13 +302,13 @@ class BaseAgentRobot {
314
302
  return this._agentRobotFactory
315
303
  }
316
304
 
317
- // 创建子技能机器人
305
+ // 创建子技能Agent
318
306
  createSubSkillAgent(id, attachTools = []) {
319
307
  const agentRobotFactory = this._getAgentRobotFactory()
320
308
  return agentRobotFactory.createSubSkillAgent(this, id, attachTools)
321
309
  }
322
310
 
323
- // 创建子机器人
311
+ // 创建子Agent
324
312
  createSubAgent(id) {
325
313
  const agentRobotFactory = this._getAgentRobotFactory()
326
314
  return agentRobotFactory.createSubAgent(this, id)
@@ -329,6 +317,7 @@ class BaseAgentRobot {
329
317
  destroy() {
330
318
  this.brain.removeAllListeners()
331
319
  this.state = -1
320
+ this.agentTree.clear()
332
321
  }
333
322
  }
334
323
 
@@ -28,6 +28,7 @@ async function createSubSkillAgent(skillName, skillType, workGoal) {
28
28
  const agentId = `${Date.now()}-${Math.floor(Math.random() * 10000)}`
29
29
  const agent = this.agentRobot.createSubSkillAgent(agentId, [tool])
30
30
  const result = await agent.executeTask(workGoal)
31
+ agent.destroy()
31
32
 
32
33
  return {
33
34
  success: true,
@@ -36,6 +37,7 @@ async function createSubSkillAgent(skillName, skillType, workGoal) {
36
37
  result,
37
38
  }
38
39
  } catch (error) {
40
+ console.error('Error in createSubSkillAgent:', error)
39
41
  return {
40
42
  success: false,
41
43
  error: error?.message || String(error),
@@ -49,6 +51,7 @@ async function createSubAgent(workGoal) {
49
51
  const agentId = `${Date.now()}-${Math.floor(Math.random() * 10000)}`
50
52
  const agent = this.agentRobot.createSubAgent(agentId)
51
53
  const result = await agent.executeTask(workGoal)
54
+ agent.destroy()
52
55
  return {
53
56
  success: true,
54
57
  agentId,
@@ -62,6 +65,15 @@ async function createSubAgent(workGoal) {
62
65
  }
63
66
  }
64
67
 
68
+ function loadAttachTool(toolName) {
69
+ try {
70
+ this.agentRobot.loadAttachTool(toolName)
71
+ return `Tool ${toolName} loaded successfully`
72
+ } catch (error) {
73
+ return `Failed to load tool ${toolName}: ${error.message}`
74
+ }
75
+ }
76
+
65
77
  const descriptions = [
66
78
  {
67
79
  type: 'function',
@@ -108,11 +120,30 @@ const descriptions = [
108
120
  },
109
121
  },
110
122
  },
123
+ {
124
+ type: 'function',
125
+ function: {
126
+ name: 'loadAttachTool',
127
+ description:
128
+ '按名称加载一个附加工具(Attach Tool)到当前agent实例中,返回加载结果信息。',
129
+ parameters: {
130
+ type: 'object',
131
+ properties: {
132
+ toolName: {
133
+ type: 'string',
134
+ description: '要加载的附加工具名称(与可用工具名称一致)。',
135
+ },
136
+ },
137
+ required: ['toolName'],
138
+ },
139
+ },
140
+ },
111
141
  ]
112
142
 
113
143
  const functions = {
114
144
  createSubSkillAgent,
115
- createSubAgent
145
+ createSubAgent,
146
+ loadAttachTool,
116
147
  }
117
148
 
118
149
  const CreateAgentTool = {
@@ -2,7 +2,7 @@
2
2
  * @Author: Roman 306863030@qq.com
3
3
  * @Date: 2026-03-17 11:59:19
4
4
  * @LastEditors: Roman 306863030@qq.com
5
- * @LastEditTime: 2026-04-13 17:46:49
5
+ * @LastEditTime: 2026-04-21 21:08:34
6
6
  * @FilePath: \deepfish\src\AgentRobot\BaseAgentRobot\tools\SystemTools.js
7
7
  * @Description: 默认扩展函数
8
8
  * @
@@ -83,7 +83,13 @@ async function requestAI(
83
83
  async function executeJSCode(code) {
84
84
  aiConsole.logSuccess('Executing JavaScript code: ')
85
85
  aiConsole.logSuccess(code)
86
-
86
+ // 检测code最后一行代码包含return,如果不包含,则返回一个错误信息,提示agent需要使用return返回结果
87
+ const codeLines = code.trim().split('\n')
88
+ const lastLine = codeLines[codeLines.length - 1].trim()
89
+ if (!lastLine.startsWith('return')) {
90
+ const error = new Error('The last line of the code must contain a return statement.')
91
+ throw error
92
+ }
87
93
  try {
88
94
  const functions = this.agentRobot.getTools()
89
95
  const Func = new Function(
@@ -97,9 +103,12 @@ async function executeJSCode(code) {
97
103
  this.logMessages.push(Array.from(arguments).join(' '))
98
104
  }
99
105
  console.log = newLog.bind(this)
100
- ${code}
106
+ function __main() {
107
+ ${code}
108
+ }
109
+ const result = await __main()
101
110
  console.log = originalLog
102
- return this.logMessages.join('\\n')
111
+ return result || this.logMessages.join('\\n')
103
112
  })()`,
104
113
  )
105
114
  const originalRequire = require
@@ -112,7 +121,6 @@ async function executeJSCode(code) {
112
121
  }
113
122
 
114
123
  const result = await Func(functions, newRequire)
115
-
116
124
  return result || ''
117
125
  } catch (error) {
118
126
  aiConsole.logError(`Error executing code: ${error.stack}`)
@@ -123,7 +131,7 @@ async function executeJSCode(code) {
123
131
  // 了解自己
124
132
  function getSelfInfo() {
125
133
  // 返回自己的代码路径、package.json路径、readme路径等基本信息,供AI有选择的了解自己,回答用户的问题
126
- const homeDir = path.resolve(__filename, '../../../../')
134
+ const homeDir = path.resolve(__dirname, '../../../../')
127
135
  const packageJson = fs.readJSONSync(path.resolve(homeDir, 'package.json'))
128
136
  return {
129
137
  config: {
@@ -192,7 +200,7 @@ const descriptions = [
192
200
  function: {
193
201
  name: 'executeJSCode',
194
202
  description:
195
- '执行JavaScript代码,返回代码执行结果。代码中可通过Tools命名空间直接调用其他工具函数(如await Tools.createFile(),注意:不需要使用require引入),Tools中引入了一些常用库可直接调用(Tools.fs="fs-extra", Tools.dayjs="dayjs", Tools.axios="axios", Tools.lodash="lodash", Tools.echarts="echarts", Tools.canvas="canvas"),支持引入自定义模块(需使用绝对路径)。注意:1.代码中不要使用__dirname获取当前目录,请使用path.resolve(".")来获取当前目录。2.执行失败时会抛出错误,成功时返回代码执行结果或空字符串。3.使用require(module_path)函数引入自定义模块,module_path为模块路径字符串,支持相对路径(如"./myModule.js")和绝对路径,返回引入的模块内容。',
203
+ '执行JavaScript代码,返回代码执行结果。代码中可通过Tools命名空间直接调用其他工具函数(如await Tools.createFile(),注意:不需要使用require引入),Tools中引入了一些常用库可直接调用(Tools.fs="fs-extra", Tools.dayjs="dayjs", Tools.axios="axios", Tools.lodash="lodash", Tools.echarts="echarts", Tools.canvas="canvas" Tools.cheerio="cheerio" Tools.puppeteer="puppeteer"),支持引入自定义模块(需使用绝对路径)。注意:1.代码中不要使用__dirname获取当前目录,请使用path.resolve(".")来获取当前目录。2.执行失败时会抛出错误,成功时返回代码执行结果或空字符串。3.使用require(module_path)函数引入自定义模块,module_path为模块路径字符串,支持相对路径(如"./myModule.js")和绝对路径,返回引入的模块内容。4.执行主函数必须使用return返回,如return main()',
196
204
  parameters: {
197
205
  type: 'object',
198
206
  properties: {
@@ -0,0 +1,66 @@
1
+ const path = require('path')
2
+ const fs = require('fs-extra')
3
+
4
+ class AgentTree {
5
+ content = null
6
+ constructor(agentRobot) {
7
+ this.agentRobot = agentRobot
8
+ this.agentTreeFilePath = path.join(
9
+ this.agentRobot.agentSpace,
10
+ 'agentTree.json',
11
+ )
12
+ this.parentAgentTree = this.agentRobot.parent?.agentTree
13
+ this.rootAgentTree = this.agentRobot.root?.agentTree
14
+ }
15
+ init() {
16
+ if (!this.rootAgentTree && !fs.pathExistsSync(this.agentTreeFilePath)) {
17
+ fs.writeJsonSync(
18
+ this.agentTreeFilePath,
19
+ { agentId: this.agentRobot.id, children: [] },
20
+ { spaces: 2 },
21
+ )
22
+ }
23
+ if (!this.rootAgentTree) {
24
+ this.content = fs.readJsonSync(this.agentTreeFilePath)
25
+ } else {
26
+ if (this.parentAgentTree && this.parentAgentTree.content.children) {
27
+ this.content = this.parentAgentTree.content.children.find(
28
+ (child) => child.agentId === this.agentRobot.id,
29
+ )
30
+ if (!this.content) {
31
+ this.content = {
32
+ agentId: this.agentRobot.id,
33
+ children: [],
34
+ type: this.agentRobot.type,
35
+ }
36
+ this.parentAgentTree.content.children.push(this.content)
37
+ fs.writeJsonSync(this.agentTreeFilePath, this.rootAgentTree.content, {
38
+ spaces: 2,
39
+ })
40
+ }
41
+ }
42
+ }
43
+ }
44
+
45
+ clear() {
46
+ if (this.rootAgentTree) {
47
+ if (this.parentAgentTree && this.parentAgentTree.content.children) {
48
+ const currentNode = this.parentAgentTree.content.children.findIndex(
49
+ (child) => child.agentId === this.agentRobot.id,
50
+ )
51
+ if (currentNode !== -1) {
52
+ this.parentAgentTree.content.children.splice(currentNode, 1)
53
+ fs.writeJsonSync(this.agentTreeFilePath, this.rootAgentTree.content, {
54
+ spaces: 2,
55
+ })
56
+ }
57
+ }
58
+ // 清除子memory
59
+ this.agentRobot.memoryFilePath &&
60
+ fs.removeSync(this.agentRobot.memoryFilePath)
61
+ }
62
+ }
63
+ }
64
+
65
+ module.exports = AgentTree
66
+
@@ -1,5 +1,6 @@
1
1
  const fs = require('fs-extra')
2
2
  const path = require('path')
3
+ const { getGlobalNodeModulesPath } = require('./node-root')
3
4
 
4
5
  class AttachmentToolType {
5
6
  static BASE_SKILL = 'BaseSkill' // 基础技能,提供技能定义的基本结构
@@ -53,8 +54,9 @@ class AttachmentToolScanner {
53
54
  const dir1 = path.resolve(__dirname, '../../../../') // 程序所在目录
54
55
  const dir2 = path.resolve(workspace, './node_modules') // 工作目录下node_modules目录
55
56
  const dir3 = path.resolve(workspace, './') // 工作目录
57
+ const dir4 = getGlobalNodeModulesPath()
56
58
  const result = []
57
- const searchDirs = [...new Set([dir1, dir2, dir3])]
59
+ const searchDirs = [...new Set([dir1, dir2, dir3, dir4])]
58
60
  for (const dirPath of searchDirs) {
59
61
  if (!fs.existsSync(dirPath)) {
60
62
  continue
@@ -132,7 +134,7 @@ class AttachmentToolScanner {
132
134
  `| ${s.name} | ${s.type} | ${s.description || s.extensionDescription} | ${s.location} | ${s.filePath || s.skillFilePath} |`,
133
135
  )
134
136
  .join('\n')
135
- if (!table) {
137
+ if (!table || !table.length) {
136
138
  return '### 暂无可用的Skills'
137
139
  }
138
140
  return `
@@ -151,16 +153,22 @@ ${table}
151
153
  `
152
154
  }
153
155
 
154
- static getClawSkillPrompt(clawSkills) {
155
- const table = clawSkills
156
+ static getClawSkillPrompt(clawSkills=[], toolCollection=[], clawSkillCollection=[]) {
157
+ const table1 = clawSkills
156
158
  .map(
157
159
  (s) =>
158
160
  `| ${s.name} | ${s.type} | ${s.description} | ${s.location} | ${s.skillFilePath} |`,
159
161
  )
160
162
  .join('\n')
161
- return `
162
- ### 可以使用的Skills
163
- 可以调用以下Skill来完成用户的请求,Skill的调用方式:
163
+ const table2 = ([].concat(toolCollection).concat(clawSkillCollection))
164
+ .map(
165
+ (s) =>
166
+ `| ${s.name} | ${s.type} | ${s.description || s.extensionDescription} | ${s.location} | ${s.filePath || s.skillFilePath} |`,
167
+ )
168
+ .join('\n')
169
+ let skills1 = `
170
+ ### 优先使用的Skills
171
+ 可以优先调用以下Skill来完成用户的请求,Skill的调用方式:
164
172
  - 使用用户请求匹配 skill description,
165
173
  - 一次只加载一个Skill,优先匹配最具体的Skill
166
174
  - 当用户请求不匹配任何Skill描述时,不加载任何Skill
@@ -169,9 +177,26 @@ ${table}
169
177
 
170
178
  | Skill | Type | Description | Location | SkillFilePath |
171
179
  |-------|------|-------------|----------|---------------|
172
- ${table}
180
+ ${table1}
173
181
  |-------|------|-------------|----------|---------------|
174
182
  `
183
+ let skills2 = `
184
+ ### 其他可以使用的Skills
185
+ 可以调用以下Skill来完成用户的请求,Skill的调用方式:
186
+ - 使用用户请求匹配 skill description,
187
+ - 一次只加载一个Skill,优先匹配最具体的Skill
188
+ - 当用户请求不匹配任何Skill描述时,不加载任何Skill
189
+ - Type类型为'ClawSkill'时,使用Skill前先使用readFile函数读取SKILL.md文件获取调用说明,通过仔细阅读说明文件学习Skill的使用方法,来完成任务
190
+ - Type类型为'BaseSkill'时,使用loadAttachTool函数加载Skill后,通过使用该Skill提供的函数来完成任务
191
+ ## Available Skills
192
+
193
+ | Skill | Type | Description | Location | FilePath |
194
+ |-------|------|-------------|----------|----------|
195
+ ${table2}
196
+ |-------|------|-------------|----------|----------|
197
+ `
198
+ return skills1 + '\n' + skills2
199
+
175
200
  }
176
201
 
177
202
  // 扫描包
@@ -203,5 +228,7 @@ ${table}
203
228
  }
204
229
  }
205
230
 
206
- module.exports = AttachmentToolScanner
207
- module.exports.AttachmentToolType = AttachmentToolType
231
+ module.exports = {
232
+ AttachmentToolScanner,
233
+ AttachmentToolType,
234
+ }
@@ -2,7 +2,7 @@
2
2
  * @Author: Roman 306863030@qq.com
3
3
  * @Date: 2026-03-23 15:23:42
4
4
  * @LastEditors: Roman 306863030@qq.com
5
- * @LastEditTime: 2026-04-07 15:56:35
5
+ * @LastEditTime: 2026-04-17 09:38:33
6
6
  * @FilePath: \deepfish\src\cli\SkillConfigManager.js
7
7
  * @Description: Skill configuration manager
8
8
  */
@@ -54,43 +54,6 @@ class SkillConfigManager {
54
54
  openDirectory(this.skillDir)
55
55
  }
56
56
 
57
- // 预加载skills,拼接提示词
58
- preLoadSkills() {
59
- const skills = this.readSkills().filter((skill) => skill.enable)
60
- if (skills.length === 0) {
61
- return '### 暂无可以使用的Skill'
62
- }
63
- const table = skills
64
- .map((s) => `| ${s.name} | ${s.description} | ${s.location} | ${s.skillFilePath} |`)
65
- .join('\n')
66
- return (
67
- `
68
- ### 可以使用的Skill
69
- 除了使用内置函数,还可以调用以下Skill来完成用户的请求,Skill的调用方式:当用户的请求匹配技能描述时,调用executeSkill函数加载对应Skill的SKILL.md说明文件,获取调用说明,通过仔细阅读说明文件学习Skill的使用方法,来完成任务。
70
- ## Available Skills
71
-
72
- | Skill | Description | Location | SkillFilePath |
73
- |-------|-------------|----------|---------------|
74
- ${table}
75
-
76
- ## Skills Policy
77
- - 当用户请求匹配 skill description 时,调用 executeSkill 函数加载对应 SKILL.md
78
- - 一次只加载一个Skill,优先匹配最具体的Skill
79
- - 当用户请求不匹配任何Skill描述时,不加载任何Skill
80
- - Skill即你可以使用的技能`
81
- )
82
- }
83
-
84
- // 调用skill,传入参数,返回结果
85
- loadSkill(skillFilePath) {
86
- // 读取skill的SKILL.md,获取调用说明
87
- if (!fs.existsSync(skillFilePath)) {
88
- aiConsole.logError(`Skill file "${skillFilePath}" does not exist.`)
89
- return null
90
- }
91
- return fs.readFileSync(skillFilePath, 'utf-8')
92
- }
93
-
94
57
  // 解析skill文件,写入到json中,获取名称、版本、作者、元数据、描述等信息
95
58
  _parseSkill(skillDirPath) {
96
59
  const skillMdPath = ['SKILL.md', 'skill.md']
@@ -168,11 +131,13 @@ ${table}
168
131
  // 如果是目录,则拷贝到skills目录下,并添加到config中
169
132
  fs.copySync(baseDir, path.join(this.skillDir, file))
170
133
  this._registerSkill(baseName)
134
+ aiConsole.logSuccess(`Skill "${baseName}" added successfully!`)
171
135
  } else if (path.extname(file) === '.zip') {
172
136
  // 如果是zip文件,则解压到skills目录下,并添加到config中
173
137
  const extractPath = path.join(this.skillDir, baseName)
174
138
  await extract(baseDir, { dir: extractPath })
175
139
  this._registerSkill(baseName)
140
+ aiConsole.logSuccess(`Skill "${baseName}" added successfully!`)
176
141
  } else {
177
142
  aiConsole.logError(`File "${file}" is not a directory or a zip file.`)
178
143
  }
@@ -244,7 +209,10 @@ ${table}
244
209
  // 解析HTML获取下载链接
245
210
  const html = response.data
246
211
  const $ = cheerio.load(html)
247
- const downloadHref = $('.skill-hero-cta a').first().attr('href')
212
+ const downloadHref = $('a').filter((i, el) => {
213
+ const href = $(el).attr('href')
214
+ return href && (href.startsWith('https://wry-manatee-359.convex.site/api/v1/download') || href.endsWith('.zip'))
215
+ }).attr('href')
248
216
 
249
217
  if (!downloadHref) {
250
218
  aiConsole.logError(`No download link found for skill "${skillName}".`)
@@ -2,20 +2,25 @@ const fs = require('fs-extra')
2
2
  const path = require('path')
3
3
  const yaml = require('js-yaml')
4
4
 
5
- function parseSkillMetadata(skillPath) {
6
- const content = fs.readFileSync(skillPath, 'utf-8');
7
-
8
- // 提取 frontmatter (--- 之间的内容)
9
- const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
5
+ function extractFrontmatter(content, skillPath) {
6
+ // Support UTF-8 BOM and both LF/CRLF line endings.
7
+ const normalizedContent = content.replace(/^\uFEFF/, '');
8
+ const frontmatterMatch = normalizedContent.match(/^---\s*\r?\n([\s\S]*?)\r?\n---\s*(?:\r?\n|$)/);
10
9
  if (!frontmatterMatch) {
11
10
  throw new Error(`No frontmatter found in ${skillPath}`);
12
11
  }
13
-
14
- const frontmatter = frontmatterMatch[1];
12
+
13
+ return frontmatterMatch[1];
14
+ }
15
+
16
+ function parseSkillMetadata(skillPath) {
17
+ const content = fs.readFileSync(skillPath, 'utf-8');
18
+
19
+ const frontmatter = extractFrontmatter(content, skillPath);
15
20
  const metadata = {};
16
21
 
17
22
  // 解析 key: value 或 key: "quoted value"
18
- const lines = frontmatter.split('\n');
23
+ const lines = frontmatter.split(/\r?\n/);
19
24
  for (const line of lines) {
20
25
  const match = line.match(/^(\w+):\s*(.+)$/);
21
26
  if (match) {
@@ -37,13 +42,8 @@ function parseSkillMetadata(skillPath) {
37
42
 
38
43
  function parseSkillMetadataYaml(skillPath) {
39
44
  const content = fs.readFileSync(skillPath, 'utf-8');
40
- const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
41
-
42
- if (!frontmatterMatch) {
43
- throw new Error(`No frontmatter found in ${skillPath}`);
44
- }
45
-
46
- const frontmatter = yaml.load(frontmatterMatch[1]);
45
+ const frontmatterContent = extractFrontmatter(content, skillPath);
46
+ const frontmatter = yaml.load(frontmatterContent);
47
47
 
48
48
  return {
49
49
  name: frontmatter.name,
package/src/index.js CHANGED
@@ -5,7 +5,7 @@ const readline = require('readline')
5
5
 
6
6
  class DeepFishAI {
7
7
  constructor(config) {
8
- // 启动一个机器人
8
+ // 启动一个Agent
9
9
  this.agentRobot = new MainAgentRobot(config)
10
10
  }
11
11