deepfish-ai 1.0.16 → 1.0.17

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/README.md CHANGED
@@ -258,7 +258,18 @@ ai ext add weather.js
258
258
 
259
259
  ```bash
260
260
  ai skill install https://clawhub.ai/TheSethRose/agent-browser
261
+ ai skill install https://clawhub.ai/steipete/weather
261
262
  ai skill ls
263
+ ai skill enable 1
264
+ ai skill disable 0
265
+ ```
266
+
267
+ **OpenClaw Skill Generation:**
268
+
269
+ ```bash
270
+ ai "Create a weather query skill"
271
+ ai skill add weather-query
272
+ ai skill enable weather-query
262
273
  ```
263
274
 
264
275
  **Media Processing:**
@@ -273,6 +284,13 @@ ai "I have ffmpeg5 installed on my system, help me convert all MP4 files in the
273
284
  ai "Classify all files under the 'model' directory into the 'model2' directory by month, date format YYYY-MM"
274
285
  ```
275
286
 
287
+ **Task List Execution:**
288
+
289
+ ```bash
290
+ ai "Create a task list: 1.xxxx; 2.xxxx; ..."
291
+ ai "Execute task list" # Start execution
292
+ ```
293
+
276
294
  ## 6. Extension Development
277
295
 
278
296
  Extensions allow you to add custom functions that AI can use in its workflows. For complex processes, you can develop them yourself or try generating extensions using this program, then register the extension with the program and use the command line to complete tasks.
@@ -346,7 +364,7 @@ module.exports = {
346
364
  Rules for automatic scanning of extension modules upon program startup:
347
365
 
348
366
  1. Scanning locations:
349
- - node_modules in the root directory
367
+ - node_modules in the npm root directory
350
368
  - node_modules in the command execution directory
351
369
  - the command execution directory itself
352
370
 
package/README_CN.md CHANGED
@@ -55,6 +55,7 @@
55
55
  - [AI服务选择](#ai服务选择)
56
56
  - [8. 使用说明](#8-使用说明)
57
57
  - [使用相对路径](#使用相对路径)
58
+ - [对话历史](#对话历史)
58
59
  - [9. 故障排除](#9-故障排除)
59
60
  - [配置问题](#配置问题)
60
61
  - [AI服务连接](#ai服务连接)
@@ -255,7 +256,18 @@ ai ext add weather.js
255
256
 
256
257
  ```bash
257
258
  ai skill install https://clawhub.ai/TheSethRose/agent-browser
259
+ ai skill install https://clawhub.ai/steipete/weather
258
260
  ai skill ls
261
+ ai skill enable 1
262
+ ai skill disable 0
263
+ ```
264
+
265
+ **OpenClaw Skill 生成:**
266
+
267
+ ```bash
268
+ ai "创建一个查询天气的skill"
269
+ ai skill add weather-query
270
+ ai skill enable weather-query
259
271
  ```
260
272
 
261
273
  **媒体处理:**
@@ -270,6 +282,13 @@ ai "我的系统上安装了ffmpeg5,帮我将目录中的所有MP4文件转换
270
282
  ai "将model目录下的所有文件按月份分类到model2目录中,日期格式为YYYY-MM"
271
283
  ```
272
284
 
285
+ **任务列表执行:**
286
+
287
+ ```bash
288
+ ai "创建一个任务列表,1.xxxx;2.xxxx;..."
289
+ ai "执行任务列表" # 开始执行
290
+ ```
291
+
273
292
  ## 6. 扩展开发
274
293
 
275
294
  扩展允许您添加AI可以在其工作流中使用的自定义函数, 对于复杂的流程也可以自行开发或尝试使用本程序生成扩展,然后将扩展注册到程序中,在使用命令行来完成任务。
@@ -342,7 +361,7 @@ module.exports = {
342
361
 
343
362
  程序启动时自动扫描扩展模块的规则:
344
363
  1. 扫描位置:
345
- - 根目录的node_modules
364
+ - npm根目录的node_modules
346
365
  - 命令执行目录的node_modules
347
366
  - 命令执行目录
348
367
  2. 扫描文件:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepfish-ai",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
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
  "bin": {
@@ -2,7 +2,7 @@
2
2
  * @Author: Roman 306863030@qq.com
3
3
  * @Date: 2026-03-16 09:18:05
4
4
  * @LastEditors: Roman 306863030@qq.com
5
- * @LastEditTime: 2026-03-25 18:33:13
5
+ * @LastEditTime: 2026-03-26 15:19:36
6
6
  * @FilePath: \deepfish\src\cli\HistoryManager.js
7
7
  * @Description: 对话历史记录、恢复
8
8
  * @
@@ -15,12 +15,16 @@ const { v4: uuidv4 } = require('uuid')
15
15
  const { logSuccess, logError } = require('../core/utils/log')
16
16
  const { openDirectory } = require('../core/utils/normal')
17
17
  // cache => [history.json, id => [message.json, logs => [log.txt]]]
18
+ // messageType:1.主会话 2.子会话(每次开始前自动清空上下文) 3.子任务会话(任务开始前,自动加载会话历史,或加载主会话历史)
18
19
  class HistoryManager {
19
20
  constructor() {
20
21
  this.configManager = GlobalVariable.configManager
21
22
  this.cacheDir = null
22
23
  this.historyFilePath = null
23
24
  this.history = null
25
+ this.messagePath = null // 主会话历史记录
26
+ this.subMessagePath = null // 子会话历史记录
27
+ this.taskMessagePath = null // 任务会话历史记录
24
28
  this.id = null
25
29
  this.logDir = null
26
30
  GlobalVariable.historyManager = this
@@ -55,15 +59,21 @@ class HistoryManager {
55
59
  }
56
60
  // 根据id创建目录,再创建一个message.json文件
57
61
  const recordDir = path.join(this.cacheDir, id)
58
- const messageFile = path.join(recordDir, 'message.json')
62
+ this.messagePath = path.join(recordDir, 'message.json')
63
+ this.subMessagePath = path.join(recordDir,'subMessage.json')
64
+ this.taskMessagePath = path.join(recordDir,'taskMessage.json')
59
65
  fs.ensureDirSync(recordDir)
60
- fs.writeJsonSync(messageFile, [], { spaces: 2 })
66
+ fs.writeJsonSync(this.messagePath, [], { spaces: 2 })
61
67
  this.history.push(newHistoryItem)
62
68
  this.updateHistory(this.history)
63
69
  this.id = newHistoryItem.id
64
70
  } else {
65
71
  historyItem.execTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
66
72
  this.id = historyItem.id
73
+ const recordDir = path.join(this.cacheDir, this.id)
74
+ this.messagePath = path.join(recordDir, 'message.json')
75
+ this.subMessagePath = path.join(recordDir,'subMessage.json')
76
+ this.taskMessagePath = path.join(recordDir,'taskMessage.json')
67
77
  }
68
78
  const logDir = path.join(this.cacheDir, this.id, 'logs')
69
79
  fs.ensureDirSync(logDir)
@@ -125,25 +135,86 @@ class HistoryManager {
125
135
  }
126
136
  }
127
137
 
128
- clearMessage() {
129
- const messageFile = path.join(this.cacheDir, this.id, 'message.json')
130
- if (fs.existsSync(messageFile)) {
131
- fs.writeJsonSync(messageFile, [], { spaces: 2 })
138
+ // 清除主会话
139
+ clearMainMessage() {
140
+ if (fs.existsSync(this.messagePath)) {
141
+ fs.writeJsonSync(this.messagePath, [], { spaces: 2 })
132
142
  logSuccess('History messages have been cleared.')
133
143
  return
134
144
  }
135
145
  logError('No history messages found to clear.')
136
146
  }
147
+
137
148
 
138
- updateMessage(message) {
139
- const messageFile = path.join(this.cacheDir, this.id, 'message.json')
140
- if (fs.pathExistsSync(messageFile)) {
141
- fs.writeJsonSync(messageFile, message, { spaces: 2 })
149
+ // 清除子会话
150
+ clearSubMessage() {
151
+ if (fs.existsSync(this.subMessagePath)) {
152
+ fs.writeJsonSync(this.subMessagePath, [], { spaces: 2 })
153
+ return
154
+ }
155
+ }
156
+
157
+ // 清除任务会话
158
+ clearTaskMessage() {
159
+ if (fs.existsSync(this.taskMessagePath)) {
160
+ fs.writeJsonSync(this.taskMessagePath, [], { spaces: 2 })
161
+ return
162
+ }
163
+ }
164
+
165
+ // 更新主会话
166
+ updateMainMessage(message) {
167
+ if (fs.pathExistsSync(this.messagePath)) {
168
+ fs.writeJsonSync(this.messagePath, message, { spaces: 2 })
169
+ }
170
+ }
171
+
172
+ // 更新子会话
173
+ updateSubMessage(message) {
174
+ fs.writeJsonSync(this.subMessagePath, message, { spaces: 2 })
175
+ }
176
+
177
+ // 更新任务会话
178
+ updateTaskMessage(message) {
179
+ fs.writeJsonSync(this.taskMessagePath, message, { spaces: 2 })
180
+ }
181
+
182
+
183
+ clearMessage(messageType = 1) {
184
+ switch (messageType) {
185
+ case 1:
186
+ this.clearMainMessage()
187
+ break
188
+ case 2:
189
+ this.clearSubMessage()
190
+ break
191
+ case 3:
192
+ this.clearTaskMessage()
193
+ break
142
194
  }
143
195
  }
144
196
 
145
- getMessage() {
146
- const messageFile = path.join(this.cacheDir, this.id, 'message.json')
197
+ updateMessage(messageType = 1, message) {
198
+ switch (messageType) {
199
+ case 1:
200
+ this.updateMainMessage(message)
201
+ break
202
+ case 2:
203
+ this.updateSubMessage(message)
204
+ break
205
+ case 3:
206
+ this.updateTaskMessage(message)
207
+ break
208
+ }
209
+ }
210
+
211
+ getMessage(messageType = 1) {
212
+ let messageFile = this.messagePath
213
+ if (messageType === 2) {
214
+ messageFile = this.subMessagePath
215
+ } else if (messageType === 3) {
216
+ messageFile = this.taskMessagePath
217
+ }
147
218
  if (!fs.pathExistsSync(messageFile)) {
148
219
  return []
149
220
  }
@@ -174,13 +245,14 @@ class HistoryManager {
174
245
  fs.writeJsonSync(this.historyFilePath, this.history, { spaces: 2 })
175
246
  }
176
247
 
177
- record(messages) {
248
+
249
+ record(messages, messageType = 1) {
178
250
  try {
179
251
  const config = this.configManager.getConfig()
180
252
  if (config.maxHistoryExpireTime === 0) {
181
253
  return false
182
254
  }
183
- this.updateMessage(messages)
255
+ this.updateMessage(messageType, messages)
184
256
  return true
185
257
  } catch (error) {
186
258
  console.error('Failed to record:', error.message)
@@ -200,10 +272,14 @@ class HistoryManager {
200
272
  )
201
273
  try {
202
274
  let logEntry = ''
203
- if (isCompress) {
204
- logEntry = `[${new Date().toISOString()}][compress] ${message.content}\n`
275
+ if (typeof message === 'string') {
276
+ logEntry = `[${new Date().toISOString()}][###############] ${message}\n`
205
277
  } else {
206
- logEntry = `[${new Date().toISOString()}][${message.role}] ${message.content}\n`
278
+ if (isCompress) {
279
+ logEntry = `[${new Date().toISOString()}][***compress***] ${message.content}\n`
280
+ } else {
281
+ logEntry = `[${new Date().toISOString()}][${message.role}] ${message.content}\n`
282
+ }
207
283
  }
208
284
  fs.appendFileSync(logFile, logEntry)
209
285
  return true
@@ -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-03-25 20:43:02
5
+ * @LastEditTime: 2026-03-26 10:34:01
6
6
  * @FilePath: \deepfish\src\cli\SkillConfigManager.js
7
7
  * @Description: Skill configuration manager
8
8
  */
@@ -9,7 +9,9 @@ extCommand
9
9
  .command("clear")
10
10
  .description("Clear the history messages for the current directory")
11
11
  .action(() => {
12
- historyManager.clearMessage();
12
+ historyManager.clearMessage(1);
13
+ historyManager.clearMessage(2);
14
+ historyManager.clearMessage(3);
13
15
  });
14
16
 
15
17
  extCommand
package/src/core/AICLI.js CHANGED
@@ -3,10 +3,22 @@ const readline = require('readline')
3
3
  const { logError } = require('./utils/log')
4
4
  const { GlobalVariable } = require('./globalVariable')
5
5
  const AIService = require('./ai-services')
6
+ const ConfigManager = require('../cli/ConfigManager')
7
+ const SkillConfigManager = require('../cli/SkillConfigManager')
8
+ const HistoryManager = require('../cli/HistoryManager')
6
9
 
7
10
  class AICLI {
8
11
  constructor(config) {
9
- this.config = config
12
+ if (!GlobalVariable.configManager) {
13
+ GlobalVariable.configManager = new ConfigManager()
14
+ }
15
+ if (!GlobalVariable.skillConfigManager) {
16
+ GlobalVariable.skillConfigManager = new SkillConfigManager()
17
+ }
18
+ if (!GlobalVariable.historyManager) {
19
+ GlobalVariable.historyManager = new HistoryManager()
20
+ }
21
+ this.config = config || GlobalVariable.configManager.getConfig()
10
22
  this.aiConfig = GlobalVariable.configManager.getCurrentAiConfig()
11
23
  this.skillConfigManager = GlobalVariable.skillConfigManager
12
24
  this.historyManager = GlobalVariable.historyManager
@@ -2,7 +2,7 @@
2
2
  * @Author: Roman 306863030@qq.com
3
3
  * @Date: 2026-03-16 09:18:05
4
4
  * @LastEditors: Roman 306863030@qq.com
5
- * @LastEditTime: 2026-03-25 15:27:58
5
+ * @LastEditTime: 2026-03-26 10:17:59
6
6
  * @FilePath: \deepfish\src\core\ai-services\AiWorker\AIMessageManager.js
7
7
  * @Description: 上下文管理-添加、自动压缩
8
8
  * @
@@ -15,11 +15,12 @@ class AIMessageManager {
15
15
  aiClient
16
16
  aiConfig
17
17
  config
18
- constructor(aiClient, config, aiConfig, messages) {
18
+ constructor(aiClient, config, aiConfig, messages, messageType = 1) {
19
19
  this.aiClient = aiClient
20
20
  this.aiConfig = aiConfig
21
21
  this.config = config
22
22
  this.messages = messages
23
+ this.messageType = messageType
23
24
  }
24
25
  reLinkMsgs(messages) {
25
26
  this.messages = messages
@@ -27,7 +28,7 @@ class AIMessageManager {
27
28
  // 添加消息
28
29
  addMsg(message) {
29
30
  this.messages.push(message)
30
- GlobalVariable.historyManager.record(this.messages)
31
+ GlobalVariable.historyManager.record(this.messages, this.messageType)
31
32
  GlobalVariable.historyManager.log(message)
32
33
  }
33
34
  // 添加tool
@@ -41,7 +42,7 @@ class AIMessageManager {
41
42
  content: content,
42
43
  }
43
44
  this.messages.push(message)
44
- GlobalVariable.historyManager.record(this.messages)
45
+ GlobalVariable.historyManager.record(this.messages, this.messageType)
45
46
  GlobalVariable.historyManager.log(message)
46
47
  }
47
48
  /**
@@ -91,7 +92,7 @@ class AIMessageManager {
91
92
  } else if (lastUserMessageIndex === messages.length - 1) {
92
93
  newMessages.push(messages[lastUserMessageIndex])
93
94
  }
94
- GlobalVariable.historyManager.record(newMessages)
95
+ GlobalVariable.historyManager.record(newMessages, this.messageType)
95
96
  } else if (messages.length === 2) {
96
97
  const summary = await this._getSummary([messages[1]])
97
98
  newMessages.push([messages[0], summary])
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * @Author: Roman 306863030@qq.com
3
3
  * @Date: 2026-03-16 09:18:05
4
- * @LastEditors: roman_123 306863030@qq.com
5
- * @LastEditTime: 2026-03-26 01:04:45
4
+ * @LastEditors: Roman 306863030@qq.com
5
+ * @LastEditTime: 2026-03-26 19:32:11
6
6
  * @FilePath: \deepfish\src\core\ai-services\AiWorker\AiAgent.js
7
7
  * @Description: 工作流循环
8
8
  * @
@@ -22,6 +22,7 @@ class AiAgent {
22
22
  config,
23
23
  aiConfig,
24
24
  extensionTools = { descriptions: [], functions: {} },
25
+ messageType = 1
25
26
  ) {
26
27
  this.aiClient = aiClient
27
28
  this.config = config
@@ -29,7 +30,8 @@ class AiAgent {
29
30
  this.maxIterations =
30
31
  config.maxIterations === -1 ? Infinity : config.maxIterations
31
32
  this.maxBlockFileSize = this.config.maxBlockFileSize || 20 // 默认20KB
32
- this.aiMessageManager = new AIMessageManager(aiClient, config, aiConfig, [])
33
+ this.aiMessageManager = new AIMessageManager(aiClient, config, aiConfig, [], messageType)
34
+ this.messageType = messageType
33
35
  this.extensionTools = extensionTools
34
36
  this.name = config.name
35
37
  }
@@ -60,12 +62,16 @@ class AiAgent {
60
62
  loadingStop(`${this.name} have finished thinking.`)
61
63
  loadingStop = null
62
64
  }
63
- logInfo(content)
64
65
  // 检查是否是任务完成的总结响应(没有工具调用且有内容)
65
66
  if (tool_calls) {
66
67
  // 执行函数
68
+ logInfo(content)
67
69
  await this.execTools(tool_calls)
68
70
  } else {
71
+ if (this.messageType === 1) {
72
+ // 只有主任务输出最后总结
73
+ logInfo(content)
74
+ }
69
75
  // 没有工具调用,结束
70
76
  break
71
77
  }
@@ -89,15 +95,12 @@ class AiAgent {
89
95
  for (const toolCall of tool_calls) {
90
96
  const { id, function: func } = toolCall
91
97
  const { name, arguments: args } = func
92
- let toolFunction = this.extensionTools.functions[name]
98
+ const toolFunctions = this.extensionTools.functions
93
99
  logInfo(`Calling tool ${toolCall.function.name}`)
94
- if (toolFunction) {
100
+ if (toolFunctions[name]) {
95
101
  try {
96
102
  const parsedArgs = typeof args === 'string' ? JSON.parse(args) : args
97
- if (name === 'readFile') {
98
- const fileInfo = await this.extensionTools.functions['getFileInfo'](
99
- parsedArgs.filePath,
100
- )
103
+ const fileInfo = await toolFunctions['getFileInfo'](parsedArgs.filePath)
101
104
  if (fileInfo && fileInfo.isFile && fileInfo.size > this.maxBlockFileSize * 1024) {
102
105
  this.aiMessageManager.addTool(id, {
103
106
  error:
@@ -107,8 +110,7 @@ class AiAgent {
107
110
  })
108
111
  continue
109
112
  }
110
- }
111
- let result = await toolFunction(...Object.values(parsedArgs))
113
+ let result = await toolFunctions[name](...Object.values(parsedArgs))
112
114
  let toolContent = JSON.stringify(result)
113
115
  if (name !== 'requestAI') {
114
116
  const MAX_CONTENT_SIZE = this.maxBlockFileSize * 1024
@@ -1,8 +1,10 @@
1
+ const { GlobalVariable } = require("../../globalVariable")
2
+
1
3
  /**
2
4
  * @Author: Roman 306863030@qq.com
3
5
  * @Date: 2026-03-17 09:12:22
4
- * @LastEditors: roman_123 306863030@qq.com
5
- * @LastEditTime: 2026-03-26 02:12:44
6
+ * @LastEditors: Roman 306863030@qq.com
7
+ * @LastEditTime: 2026-03-26 16:56:47
6
8
  * @FilePath: \deepfish\src\core\ai-services\AiWorker\AiPrompt.js
7
9
  * @Description: AI请求提示词
8
10
  * @
@@ -10,7 +12,9 @@
10
12
  const currentDir = process.cwd()
11
13
  const osType = process.platform
12
14
 
13
- const AiAgentSystemPrompt = `
15
+ const AiAgentSystemPrompt = () => {
16
+ const maxBlockFileSize = GlobalVariable.aiCli.config.maxBlockFileSize || 20
17
+ return `
14
18
  你叫DeepFish, 是一个严格按规则执行任务的智能体,不能违反任何系统限制。
15
19
  ### 基础环境信息
16
20
  当前工作目录:${currentDir}
@@ -21,9 +25,9 @@ const AiAgentSystemPrompt = `
21
25
  系统中内置了一些可以直接调用的工具函数,如可调用 executeJSCode 运行 Node.js 代码处理复杂逻辑;可调用 executeCommand 运行系统命令行工具(如 git、npm 等),工具调用需确保语法/指令符合当前操作系统规范(Windows/macOS/Linux 区分)。
22
26
 
23
27
  ### 大文本文件处理规则(分步执行)
24
- 处理长文档等大文件(单文件>20KB)时,必须按以下步骤分块处理:
28
+ 处理长文档等大文件(单文件>${maxBlockFileSize}KB)时,必须按以下步骤分块处理:
25
29
  1. 预处理:先执行文件大小/结构检查(如通过命令行/JS 代码获取文件大小、判断文件格式),输出检查结果;
26
- 2. 分块规则:按5KB-10KB/块拆分文件,拆分后每个块生成独立临时文件(命名格式:tmp_{原文件名}_chunk{序号}.tmp);
30
+ 2. 分块规则:按5KB-10KB/块拆分文件,拆分后每个块生成独立临时文件(命名格式:tmp_block_{原文件名}_chunk{序号}.tmp);
27
31
  3. 处理逻辑:翻译/总结/分析类任务逐块处理,每块处理完成后记录结果,最后合并所有块的结果生成最终文件;
28
32
  4. 合并校验:合并后需校验结果完整性(如总字符数匹配、无内容缺失),确保分块处理无遗漏。
29
33
 
@@ -31,12 +35,15 @@ const AiAgentSystemPrompt = `
31
35
  1. 最优路径优先:执行前必须先规划最少步骤的操作路径,明确「先做什么、再做什么、哪些可省略」,避免重复操作和无效步骤;
32
36
  2. 异常反馈:操作失败(如命令执行报错、文件不存在)时,需明确说明「失败原因+可尝试的解决方案」,而非仅提示“操作失败”;
33
37
  3. 结果校验:任务完成后,需简单校验结果是否符合用户目标(如文件是否生成、内容是否完整),并向用户反馈校验结果。
34
- 4. 如果执行任务过程中需要安装软件、工具或执行"npm install"命令,必须通过调用用户交互函数与用户交互,等待用户确认后再执行安装。
35
- 5. 任务执行过程中,产生的所有临时文件(如分块文件、测试文件等)必须以"tmp_"为前缀命名,并在任务完成后删除这些临时文件,确保工作目录整洁。
38
+ 4. 如果执行任务过程中需要安装依赖、软件或工具,必须通过调用用户交互函数与用户交互,等待用户确认后再执行安装,除非用户明确说明执行过程中使用静默模式。
39
+ 5. 任务执行过程中,产生的所有临时文件(如分块文件、测试文件等)必须以"tmp_"为前缀命名,如"tmp_block_filename.txt、tmp_test_filename.txt、tmp_bak_filename.txt",并在任务完成后删除这些临时文件,确保工作目录整洁。
36
40
  `
41
+ }
37
42
 
38
- const SkillAiAgentSystemPrompt = `
39
- 你叫DeepFish, 是一个能够使用Skill完成任务的智能体,不能违反任何系统限制。用户会给你一个明确的目标,这是整个任务环节中的一个子任务,你需要仔细分析目标,结合Skill文档来完成这项任务,如果不能借助Skill完成则直接返回原因。
43
+ const SkillAiAgentSystemPrompt = () => {
44
+ const maxBlockFileSize = GlobalVariable.aiCli.config.maxBlockFileSize || 20
45
+ return `
46
+ 你叫SkillDeepFish, 是一个能够使用Skill完成任务的智能体,不能违反任何系统限制。用户会给你一个明确的目标,这是整个任务环节中的一个子任务,你需要仔细分析目标,结合Skill文档来完成这项任务,如果不能借助Skill完成则直接返回原因。
40
47
  ### 基础环境信息
41
48
  当前工作目录:${currentDir}
42
49
  操作系统类型:${osType}
@@ -46,9 +53,9 @@ const SkillAiAgentSystemPrompt = `
46
53
  工具调用需确保语法/指令符合当前操作系统规范(Windows/macOS/Linux 区分)。
47
54
 
48
55
  ### 大文本文件处理规则(分步执行)
49
- 处理长文档等大文件(单文件>20KB)时,必须按以下步骤分块处理:
56
+ 处理长文档等大文件(单文件>${maxBlockFileSize}KB)时,必须按以下步骤分块处理:
50
57
  1. 预处理:先执行文件大小/结构检查(如通过命令行/JS 代码获取文件大小、判断文件格式),输出检查结果;
51
- 2. 分块规则:按5KB-10KB/块拆分文件,拆分后每个块生成独立临时文件(命名格式:tmp_{原文件名}_chunk{序号}.tmp);
58
+ 2. 分块规则:按5KB-10KB/块拆分文件,拆分后每个块生成独立临时文件(命名格式:tmp_block_{原文件名}_chunk{序号}.tmp);
52
59
  3. 处理逻辑:翻译/总结/分析类任务逐块处理,每块处理完成后记录结果,最后合并所有块的结果生成最终文件;
53
60
  4. 合并校验:合并后需校验结果完整性(如总字符数匹配、无内容缺失),确保分块处理无遗漏。
54
61
 
@@ -57,13 +64,16 @@ const SkillAiAgentSystemPrompt = `
57
64
  2. 使用Skill.md中列出的技能,避免使用其他技能;
58
65
  3. 可以使用工具函数(如 executeJSCode、executeCommand)来辅助使用技能,但必须确保工具调用符合当前操作系统规范;
59
66
  4. 如果发现不能使用Skill完成任务,则直接说明原因,不要尝试使用其他工具或技能来完成任务;
60
- 5. 如果需要安装软件或工具来完成任务,必须通过调用用户交互函数与用户交互,等待用户确认后再执行安装。
67
+ 5. 如果需要安装软件或工具来完成任务,必须通过调用用户交互函数与用户交互,除非用户明确说明执行过程中使用静默模式,等待用户确认后再执行安装。
61
68
  6. 任务完成后,反馈任务执行结果。
62
- 7. 任务执行过程中,产生的所有临时文件(如分块文件、测试文件等)必须以"tmp_"为前缀命名,并在任务完成后删除这些临时文件,确保工作目录整洁。
69
+ 7. 任务执行过程中,产生的所有临时文件(如分块文件、测试文件等)必须以"tmp_"为前缀命名,如"tmp_block_filename.txt、tmp_test_filename.txt、tmp_bak_filename.txt",并在任务完成后删除这些临时文件,确保工作目录整洁。
63
70
  `
71
+ }
64
72
 
65
- const TestAiAgentSystemPrompt = `
66
- 你叫DeepFish, 是一个调用工具函数完成测试任务的智能体,不能违反任何系统限制。用户会给你一个明确的测试目标,这是整个测试环节中的一个子任务,你需要仔细分析目标,结合工具函数来完成这项测试,如果不能借助工具函数完成则直接返回原因。
73
+ const TestAiAgentSystemPrompt = () => {
74
+ const maxBlockFileSize = GlobalVariable.aiCli.config.maxBlockFileSize || 20
75
+ return `
76
+ 你叫TestDeepFish, 是一个调用工具函数完成测试任务的智能体,不能违反任何系统限制。用户会给你一个明确的测试目标,这是整个测试环节中的一个子任务,你需要仔细分析目标,结合工具函数来完成这项测试,如果不能借助工具函数完成则直接返回原因。
67
77
  ### 基础环境信息
68
78
  当前工作目录:${currentDir}
69
79
  操作系统类型:${osType}
@@ -72,17 +82,54 @@ const TestAiAgentSystemPrompt = `
72
82
  ### 工具使用规则
73
83
  工具调用需确保语法/指令符合当前操作系统规范(Windows/macOS/Linux 区分)。
74
84
 
85
+ ### 大文本文件处理规则(分步执行)
86
+ 处理长文档等大文件(单文件>${maxBlockFileSize}KB)时,必须按以下步骤分块处理:
87
+ 1. 预处理:先执行文件大小/结构检查(如通过命令行/JS 代码获取文件大小、判断文件格式),输出检查结果;
88
+ 2. 分块规则:按5KB-10KB/块拆分文件,拆分后每个块生成独立临时文件(命名格式:tmp_block_{原文件名}_chunk{序号}.tmp);
89
+ 3. 处理逻辑:翻译/总结/分析类任务逐块处理,每块处理完成后记录结果,最后合并所有块的结果生成最终文件;
90
+ 4. 合并校验:合并后需校验结果完整性(如总字符数匹配、无内容缺失),确保分块处理无遗漏。
91
+
75
92
  ### 测试规则
76
93
  1. 仔细分析测试目标,确保完全理解测试需求和预期结果;
77
- 2. 在测试过程中可以通过创建前缀为"test_"的临时文件辅助测试,完成后需删除这些临时文件;
94
+ 2. 在测试过程中可以通过创建前缀为"tmp_test_"的临时文件辅助测试,完成后需删除这些临时文件;
78
95
  3. 在测试过程中随意不能修改原有的文件内容;
79
96
  4. 如果发现不能使用工具函数完成测试任务,则直接说明原因,不要做过多尝试;
80
97
  5. 任务完成后,反馈测试执行结果。
81
- 6. 任务执行过程中,产生的所有临时文件(如分块文件、测试文件等)必须以"tmp_"为前缀命名,并在任务完成后删除这些临时文件,确保工作目录整洁。
98
+ 6. 任务执行过程中,产生的所有临时文件(如分块文件、测试文件等)必须以"tmp_block_"为前缀命名,如"tmp_block_filename.txt、tmp_test_filename.txt、tmp_bak_filename.txt",并在任务完成后删除这些临时文件,确保工作目录整洁。
82
99
  `
100
+ }
101
+
102
+ const TaskAiAgentSystemPrompt = () => {
103
+ const maxBlockFileSize = GlobalVariable.aiCli.config.maxBlockFileSize || 20
104
+ return `
105
+ 你叫SubTaskDeepFish, 是一个严格按规则执行子任务的智能体,不能违反任何系统限制。
106
+ ### 基础环境信息
107
+ 当前工作目录:${currentDir}
108
+ 操作系统类型:${osType}
109
+ 语言类型: 与用户输入语言一致
110
+
111
+ ### 工具使用规则
112
+ 系统中内置了一些可以直接调用的工具函数,如可调用 executeJSCode 运行 Node.js 代码处理复杂逻辑;可调用 executeCommand 运行系统命令行工具(如 git、npm 等),工具调用需确保语法/指令符合当前操作系统规范(Windows/macOS/Linux 区分)。
113
+
114
+ ### 大文本文件处理规则(分步执行)
115
+ 处理长文档等大文件(单文件>${maxBlockFileSize}KB)时,必须按以下步骤分块处理:
116
+ 1. 预处理:先执行文件大小/结构检查(如通过命令行/JS 代码获取文件大小、判断文件格式),输出检查结果;
117
+ 2. 分块规则:按5KB-10KB/块拆分文件,拆分后每个块生成独立临时文件(命名格式:tmp_block_{原文件名}_chunk{序号}.tmp);
118
+ 3. 处理逻辑:翻译/总结/分析类任务逐块处理,每块处理完成后记录结果,最后合并所有块的结果生成最终文件;
119
+ 4. 合并校验:合并后需校验结果完整性(如总字符数匹配、无内容缺失),确保分块处理无遗漏。
120
+
121
+ ### 核心执行原则
122
+ 1. 最优路径优先:执行前必须先规划最少步骤的操作路径,明确「先做什么、再做什么、哪些可省略」,避免重复操作和无效步骤;
123
+ 2. 异常反馈:操作失败(如命令执行报错、文件不存在)时,需明确说明「失败原因+可尝试的解决方案」,而非仅提示“操作失败”;
124
+ 3. 结果校验:任务完成后,需简单校验结果是否符合用户目标(如文件是否生成、内容是否完整),并向用户反馈校验结果。
125
+ 4. 如果执行任务过程中需要安装依赖、软件或工具,必须通过调用用户交互函数与用户交互,等待用户确认后再执行安装,除非用户明确说明执行过程中使用静默模式。
126
+ 5. 任务执行过程中,产生的所有临时文件(如分块文件、测试文件、备份文件等)必须以"tmp_"为前缀命名,如"tmp_block_filename.txt、tmp_test_filename.txt、tmp_bak_filename.txt", 并在任务完成后删除这些临时文件,确保工作目录整洁。
127
+ `
128
+ }
83
129
 
84
130
  module.exports = {
85
131
  AiAgentSystemPrompt,
86
132
  SkillAiAgentSystemPrompt,
87
133
  TestAiAgentSystemPrompt,
134
+ TaskAiAgentSystemPrompt
88
135
  }