deepfish-ai 1.0.19 → 1.0.20
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 +2 -1
- package/src/AgentRobot/AgentRobotFactory/MainAgentRobot.js +6 -21
- package/src/AgentRobot/AgentRobotFactory/SubAgentRobot.js +5 -12
- package/src/AgentRobot/AgentRobotFactory/SubSkillAgentRobot.js +22 -17
- package/src/AgentRobot/AgentRobotFactory/index.js +4 -9
- package/src/AgentRobot/BaseAgentRobot/Brain.js +8 -2
- package/src/AgentRobot/BaseAgentRobot/index.js +34 -45
- package/src/AgentRobot/BaseAgentRobot/tools/CreateAgentTools.js +32 -1
- package/src/AgentRobot/BaseAgentRobot/tools/SystemTools.js +3 -4
- package/src/AgentRobot/BaseAgentRobot/utils/AgentTree.js +66 -0
- package/src/AgentRobot/BaseAgentRobot/utils/AttachmentToolScanner.js +37 -10
- package/src/cli/SkillConfigManager.js +7 -39
- package/src/cli/SkillParser.js +15 -15
- package/src/index.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deepfish-ai",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.20",
|
|
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.
|
|
49
|
-
|
|
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
|
-
|
|
30
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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 {
|
|
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 = '' //
|
|
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 //
|
|
39
|
-
type = 'main' //
|
|
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
|
-
|
|
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
|
})
|
|
@@ -282,6 +267,9 @@ class BaseAgentRobot {
|
|
|
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-
|
|
5
|
+
* @LastEditTime: 2026-04-20 17:47:12
|
|
6
6
|
* @FilePath: \deepfish\src\AgentRobot\BaseAgentRobot\tools\SystemTools.js
|
|
7
7
|
* @Description: 默认扩展函数
|
|
8
8
|
* @
|
|
@@ -112,7 +112,6 @@ async function executeJSCode(code) {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
const result = await Func(functions, newRequire)
|
|
115
|
-
|
|
116
115
|
return result || ''
|
|
117
116
|
} catch (error) {
|
|
118
117
|
aiConsole.logError(`Error executing code: ${error.stack}`)
|
|
@@ -123,7 +122,7 @@ async function executeJSCode(code) {
|
|
|
123
122
|
// 了解自己
|
|
124
123
|
function getSelfInfo() {
|
|
125
124
|
// 返回自己的代码路径、package.json路径、readme路径等基本信息,供AI有选择的了解自己,回答用户的问题
|
|
126
|
-
const homeDir = path.resolve(
|
|
125
|
+
const homeDir = path.resolve(__dirname, '../../../../')
|
|
127
126
|
const packageJson = fs.readJSONSync(path.resolve(homeDir, 'package.json'))
|
|
128
127
|
return {
|
|
129
128
|
config: {
|
|
@@ -192,7 +191,7 @@ const descriptions = [
|
|
|
192
191
|
function: {
|
|
193
192
|
name: 'executeJSCode',
|
|
194
193
|
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")和绝对路径,返回引入的模块内容。',
|
|
194
|
+
'执行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")和绝对路径,返回引入的模块内容。',
|
|
196
195
|
parameters: {
|
|
197
196
|
type: 'object',
|
|
198
197
|
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
|
|
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
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
-
${
|
|
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 =
|
|
207
|
-
|
|
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-
|
|
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 = $('
|
|
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}".`)
|
package/src/cli/SkillParser.js
CHANGED
|
@@ -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
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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,
|