deepfish-ai 1.0.25 → 1.0.26
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 +48 -9
- package/README_CN.md +50 -11
- package/package.json +3 -2
- package/src/AgentRobot/BaseAgentRobot/Brain.js +1 -0
- package/src/AgentRobot/BaseAgentRobot/index.js +12 -1
- package/src/AgentRobot/BaseAgentRobot/tools/CreateAgentTools.js +1 -0
- package/src/AgentRobot/BaseAgentRobot/tools/FileTools.js +114 -22
- package/src/AgentRobot/BaseAgentRobot/tools/GenerateTools.js +4 -4
- package/src/AgentRobot/BaseAgentRobot/tools/SystemTools.js +22 -0
- package/src/AgentRobot/BaseAgentRobot/utils/AIToolManager.js +1 -0
- package/src/cli/index.js +1 -1
package/README.md
CHANGED
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
- [Initial Setup](#initial-setup)
|
|
44
44
|
- [Configuration Commands](#configuration-commands)
|
|
45
45
|
- [Configuration File Structure](#configuration-file-structure)
|
|
46
|
+
- [Directory Structure](#directory-structure)
|
|
46
47
|
- [5. Usage](#5-usage)
|
|
47
48
|
- [Interactive Mode](#interactive-mode)
|
|
48
49
|
- [Direct Command Mode](#direct-command-mode)
|
|
@@ -125,7 +126,7 @@ ai config add
|
|
|
125
126
|
|
|
126
127
|
This will prompt you to configure the following:
|
|
127
128
|
|
|
128
|
-
- **AI Service Type**: Choose DeepSeek, Ollama, or OpenAI
|
|
129
|
+
- **AI Service Type**: Choose DeepSeek, MiniMax, Qwen, Ollama, or OpenAI
|
|
129
130
|
- **API Base URL**: Default URL provided for each service
|
|
130
131
|
- **Model Name**: Choose the AI model to use
|
|
131
132
|
- **API Key**: Required for DeepSeek and OpenAI
|
|
@@ -156,8 +157,8 @@ ai skill disable <name|index> # Disable a skill by name or index, exp: ai skill
|
|
|
156
157
|
ai skill dir # Open the skill directory
|
|
157
158
|
|
|
158
159
|
# Memory commands
|
|
159
|
-
ai
|
|
160
|
-
ai
|
|
160
|
+
ai memory clear # Clear the history messages for the current directory
|
|
161
|
+
ai memory dir # Open the memory directory
|
|
161
162
|
```
|
|
162
163
|
|
|
163
164
|
### Configuration File Structure
|
|
@@ -181,16 +182,54 @@ export default {
|
|
|
181
182
|
],
|
|
182
183
|
currentAi: "default", // Name of the currently active AI configuration
|
|
183
184
|
maxIterations: -1, // Maximum iterations for AI to complete the workflow, -1 for unlimited
|
|
184
|
-
maxMessagesLength: 150000, // Maximum compression length, -1 for unlimited
|
|
185
|
-
maxMessagesCount: 100, // Maximum compression count, -1 for unlimited
|
|
186
185
|
maxMemoryExpireTime: 30, // Maximum session expiration time in days, -1 for unlimited, 0 to disable recording
|
|
187
186
|
maxLogExpireTime: 3, // Log expiration time in days, -1 for unlimited, 0 to disable recording
|
|
188
187
|
maxBlockFileSize: 20, // Maximum block file size in KB; files exceeding this size need to be processed in blocks
|
|
189
|
-
|
|
188
|
+
isThinkPrint: true, // Whether to print the thinking process
|
|
190
189
|
encoding: "auto", // Command line encoding format, can be set to utf-8, gbk, etc., or auto/empty for auto-detection
|
|
190
|
+
EMBEDDING_API: "", // Embedding API endpoint URL
|
|
191
|
+
EMBEDDING_API_KEY: "", // Embedding API key
|
|
191
192
|
};
|
|
192
193
|
```
|
|
193
194
|
|
|
195
|
+
### Directory Structure
|
|
196
|
+
|
|
197
|
+
DeepFish uses `.deepfish-ai` as the default working directory. You can open it directly with:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
ai config dir
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Default paths:
|
|
204
|
+
|
|
205
|
+
- Windows: `C:/Users/<username>/.deepfish-ai`
|
|
206
|
+
- macOS/Linux: `~/.deepfish-ai`
|
|
207
|
+
|
|
208
|
+
Based on the structure in DevPlan, the directory layout is:
|
|
209
|
+
|
|
210
|
+
```text
|
|
211
|
+
.deepfish-ai/
|
|
212
|
+
├─ config.js # Global configuration
|
|
213
|
+
├─ user-info/
|
|
214
|
+
│ └─ user.md # User profile data
|
|
215
|
+
├─ clawSkills/
|
|
216
|
+
│ ├─ clawSkills.json # OpenClaw skill index
|
|
217
|
+
│ └─ <skill>/
|
|
218
|
+
│ └─ SKILL.md # Single skill definition
|
|
219
|
+
└─ memery/
|
|
220
|
+
├─ agentRecord.json # Workspace to main-agent mapping
|
|
221
|
+
└─ <main-agent-id>/
|
|
222
|
+
├─ memery.json # Main agent memory
|
|
223
|
+
├─ memery-<sub-agent-id>.json # Sub-agent memory
|
|
224
|
+
├─ agentTree.json # Agent hierarchy
|
|
225
|
+
├─ bakup/
|
|
226
|
+
│ └─ <timestamp>/
|
|
227
|
+
│ ├─ record.json # Backup operation record
|
|
228
|
+
│ └─ <uuid>.* # Backup files
|
|
229
|
+
└─ logs/
|
|
230
|
+
└─ log-{YYYY-MM-DD HH}.txt # Hourly rolling logs
|
|
231
|
+
```
|
|
232
|
+
|
|
194
233
|
## 5. Usage
|
|
195
234
|
|
|
196
235
|
### Interactive Mode
|
|
@@ -388,8 +427,8 @@ Conversation history is created on a per-directory basis — each execution dire
|
|
|
388
427
|
|
|
389
428
|
Conversation history will be automatically cleared after a configurable period (controlled by the `maxMemoryExpireTime` field in the configuration file, default is 30 days). You can also manage it manually:
|
|
390
429
|
|
|
391
|
-
- `ai
|
|
392
|
-
- `ai
|
|
430
|
+
- `ai memory dir` — Open the memory directory to view stored conversation contexts
|
|
431
|
+
- `ai memory clear` — Manually clear the conversation history for the current directory
|
|
393
432
|
|
|
394
433
|
## 9. Troubleshooting
|
|
395
434
|
|
|
@@ -404,7 +443,7 @@ ai config reset
|
|
|
404
443
|
### AI Service Connection
|
|
405
444
|
|
|
406
445
|
- **Ollama**: Ensure Ollama is running locally on port 11434
|
|
407
|
-
- **DeepSeek/OpenAI**: Verify your API key is correct and you have sufficient quota
|
|
446
|
+
- **DeepSeek/MiniMax/Qwen/OpenAI**: Verify your API key is correct and you have sufficient quota
|
|
408
447
|
|
|
409
448
|
### Extension Not Loading
|
|
410
449
|
|
package/README_CN.md
CHANGED
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
- [初始设置](#初始设置)
|
|
45
45
|
- [配置命令](#配置命令)
|
|
46
46
|
- [配置文件结构](#配置文件结构)
|
|
47
|
+
- [目录结构说明](#目录结构说明)
|
|
47
48
|
- [5. 使用方法](#5-使用方法)
|
|
48
49
|
- [交互模式](#交互模式)
|
|
49
50
|
- [直接命令模式](#直接命令模式)
|
|
@@ -123,7 +124,7 @@ ai config add
|
|
|
123
124
|
|
|
124
125
|
这将提示你配置以下内容:
|
|
125
126
|
|
|
126
|
-
- **AI服务类型**:选择DeepSeek、Ollama或OpenAI
|
|
127
|
+
- **AI服务类型**:选择DeepSeek、MiniMax、Qwen、Ollama或OpenAI
|
|
127
128
|
- **API基础URL**:为每个服务提供默认URL
|
|
128
129
|
- **模型名称**:选择要使用的AI模型
|
|
129
130
|
- **API密钥**:DeepSeek和OpenAI需要
|
|
@@ -154,8 +155,8 @@ ai skill disable <name|index> # 通过名称或索引禁用 skill, exp: ai skill
|
|
|
154
155
|
ai skill dir # 打开 skill 目录
|
|
155
156
|
|
|
156
157
|
# 记忆命令
|
|
157
|
-
ai
|
|
158
|
-
ai
|
|
158
|
+
ai memory clear # 清除当前目录的对话历史
|
|
159
|
+
ai memory dir # 打开记忆目录
|
|
159
160
|
```
|
|
160
161
|
|
|
161
162
|
### 配置文件结构
|
|
@@ -179,16 +180,54 @@ export default {
|
|
|
179
180
|
],
|
|
180
181
|
currentAi: "default", // 当前活动的AI配置名称
|
|
181
182
|
maxIterations: -1, // ai完成工作流的最大迭代次数,-1表示无限制
|
|
182
|
-
maxMessagesLength: 150000, // 最大压缩长度,-1表示无限制
|
|
183
|
-
maxMessagesCount: 100, // 最大压缩数量,-1表示无限制
|
|
184
183
|
maxMemoryExpireTime: 30, // 整个会话的最大过期时间,单位天,-1表示无限制,0表示不记录
|
|
185
184
|
maxLogExpireTime: 3, // 日志过期时间,单位天,-1表示无限制,0表示不记录
|
|
186
185
|
maxBlockFileSize: 20, // 最大分块文件大小,单位KB;超过该大小的文件需要分块处理
|
|
187
|
-
|
|
186
|
+
isThinkPrint: true, // 是否打印思考过程
|
|
188
187
|
encoding: "auto", // 命令行编码格式,可设置为utf-8、gbk等,也可以设置成auto或空值自动判断
|
|
188
|
+
EMBEDDING_API: "", // 向量化接口地址
|
|
189
|
+
EMBEDDING_API_KEY: "", // 向量化接口密钥
|
|
189
190
|
};
|
|
190
191
|
```
|
|
191
192
|
|
|
193
|
+
### 目录结构说明
|
|
194
|
+
|
|
195
|
+
DeepFish 默认工作目录为 `.deepfish-ai`,可通过以下命令直接打开:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
ai config dir
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
默认路径:
|
|
202
|
+
|
|
203
|
+
- Windows: `C:/Users/<用户名>/.deepfish-ai`
|
|
204
|
+
- macOS/Linux: `~/.deepfish-ai`
|
|
205
|
+
|
|
206
|
+
参考 DevPlan 的目录结构示例如下:
|
|
207
|
+
|
|
208
|
+
```text
|
|
209
|
+
.deepfish-ai/
|
|
210
|
+
├─ config.js # 全局配置
|
|
211
|
+
├─ user-info/
|
|
212
|
+
│ └─ user.md # 用户信息
|
|
213
|
+
├─ clawSkills/
|
|
214
|
+
│ ├─ clawSkills.json # OpenClaw 技能索引
|
|
215
|
+
│ └─ <skill>/
|
|
216
|
+
│ └─ SKILL.md # 单个技能说明
|
|
217
|
+
└─ memery/
|
|
218
|
+
├─ agentRecord.json # 工作目录与主 agent 映射
|
|
219
|
+
└─ <主agent编号>/
|
|
220
|
+
├─ memery.json # 主 agent 记忆
|
|
221
|
+
├─ memery-<子agent编号>.json # 子 agent 记忆
|
|
222
|
+
├─ agentTree.json # agent 组织结构
|
|
223
|
+
├─ bakup/
|
|
224
|
+
│ └─ <时间戳>/
|
|
225
|
+
│ ├─ record.json # 备份记录
|
|
226
|
+
│ └─ <uuid>.* # 备份文件
|
|
227
|
+
└─ logs/
|
|
228
|
+
└─ log-{YYYY-MM-DD HH}.txt # 按小时滚动日志
|
|
229
|
+
```
|
|
230
|
+
|
|
192
231
|
## 5. 使用方法
|
|
193
232
|
|
|
194
233
|
### 交互模式
|
|
@@ -378,14 +417,14 @@ AI始终使用相对于当前工作目录的相对路径。
|
|
|
378
417
|
|
|
379
418
|
### 对话历史
|
|
380
419
|
|
|
381
|
-
对话历史是以程序执行目录为单位创建的,每个程序的执行目录会对应一个独立的 Agent 上下文。这意味着在不同目录下启动的对话是相互独立的。
|
|
382
|
-
|
|
420
|
+
对话历史是以程序执行目录为单位创建的,每个程序的执行目录会对应一个独立的 Agent 上下文。这意味着在不同目录下启动的对话是相互独立的。
|
|
421
|
+
|
|
383
422
|
> **⚠️ 重要提示:** AI上下文是以目录为单位的,一个目录对应一个上下文。**请不要在同一个目录下开启两个命令行对话框**,以免造成上下文冲突和意外行为。
|
|
384
423
|
|
|
385
424
|
对话历史会在一定时间内自动清除(通过配置文件中的 `maxMemoryExpireTime` 字段控制,默认为 30 天)。您也可以手动管理对话历史:
|
|
386
425
|
|
|
387
|
-
- `ai
|
|
388
|
-
- `ai
|
|
426
|
+
- `ai memory dir` — 打开记忆目录,查看已存储的对话上下文
|
|
427
|
+
- `ai memory clear` — 清除当前目录的对话历史
|
|
389
428
|
|
|
390
429
|
## 9. 故障排除
|
|
391
430
|
|
|
@@ -400,7 +439,7 @@ ai config reset
|
|
|
400
439
|
### AI服务连接
|
|
401
440
|
|
|
402
441
|
- **Ollama**:确保Ollama在本地11434端口上运行
|
|
403
|
-
- **DeepSeek/OpenAI**:验证您的API密钥是否正确,并且您有足够的额度
|
|
442
|
+
- **DeepSeek/MiniMax/Qwen/OpenAI**:验证您的API密钥是否正确,并且您有足够的额度
|
|
404
443
|
|
|
405
444
|
### 扩展未加载
|
|
406
445
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deepfish-ai",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.26",
|
|
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",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"ai": "src/cli/index.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
12
|
+
"build": "package-offline.bat"
|
|
12
13
|
},
|
|
13
14
|
"keywords": [
|
|
14
15
|
"ai",
|
|
@@ -5,6 +5,7 @@ const BrainEvent = require('./BrainEvent.js')
|
|
|
5
5
|
const ScreenPrinter = require('./ScreenPrinter.js')
|
|
6
6
|
const { HandEvent, Hand } = require('./Hand.js')
|
|
7
7
|
const AIToolManager = require('./utils/AIToolManager.js')
|
|
8
|
+
const dayjs = require('dayjs')
|
|
8
9
|
|
|
9
10
|
class BaseAgentRobot {
|
|
10
11
|
id = '' // Agentid
|
|
@@ -187,6 +188,7 @@ class BaseAgentRobot {
|
|
|
187
188
|
当前工作目录:${workspace}
|
|
188
189
|
操作系统类型:${osType}
|
|
189
190
|
语言类型: 与用户输入语言一致
|
|
191
|
+
会话开始时间: ${dayjs().format('YYYY-MM-DD HH')}
|
|
190
192
|
|
|
191
193
|
### 工具使用
|
|
192
194
|
执行任务前,应仔细阅读工具描述以及可以使用的Skills的描述内容,优先使用匹配到的工具或技能,避免自己发挥。
|
|
@@ -207,7 +209,7 @@ class BaseAgentRobot {
|
|
|
207
209
|
|
|
208
210
|
### 用户信息
|
|
209
211
|
#### 用户信息记录规则
|
|
210
|
-
|
|
212
|
+
当对话中出现用户信息时,如个人基础信息(如姓名、昵称、年龄、职业、兴趣、性格特征等)、AI的基础信息(如昵称、性格特征等)、操作习惯、代码习惯、阅读习惯、用户常用目录等,必须使用用户信息读写函数进行记录。
|
|
211
213
|
|
|
212
214
|
#### 当前用户信息
|
|
213
215
|
----user info start----
|
|
@@ -216,6 +218,15 @@ ${this.toolManager.functions.readUserInfo()}
|
|
|
216
218
|
`
|
|
217
219
|
}
|
|
218
220
|
|
|
221
|
+
// 更新系统提示词中的会话开始时间
|
|
222
|
+
updateSessionTime() {
|
|
223
|
+
const newTime = dayjs().format('YYYY-MM-DD HH')
|
|
224
|
+
this.systemPrompt = this.systemPrompt.replace(
|
|
225
|
+
/会话开始时间: \d{4}-\d{2}-\d{2} \d{2}/,
|
|
226
|
+
`会话开始时间: ${newTime}`,
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
|
|
219
230
|
async executeTask(goal) {
|
|
220
231
|
const taskId = `task-${Date.now()}`
|
|
221
232
|
this.logger.logExecTime(taskId, 'execute task goal')
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @Author: Roman 306863030@qq.com
|
|
3
3
|
* @Date: 2026-03-17 11:59:19
|
|
4
|
-
* @LastEditors:
|
|
5
|
-
* @LastEditTime: 2026-04-
|
|
4
|
+
* @LastEditors: roman_123 306863030@qq.com
|
|
5
|
+
* @LastEditTime: 2026-04-25 01:15:56
|
|
6
6
|
* @FilePath: \deepfish\src\AgentRobot\BaseAgentRobot\tools\FileTools.js
|
|
7
7
|
* @Description: 文件处理扩展函数
|
|
8
8
|
* @
|
|
@@ -46,7 +46,9 @@ async function modifyFile(filePath, content) {
|
|
|
46
46
|
const fullPath = path.resolve(process.cwd(), filePath)
|
|
47
47
|
|
|
48
48
|
if (!fs.existsSync(fullPath)) {
|
|
49
|
-
return createErrorResult(`File does not exist: ${fullPath}`, {
|
|
49
|
+
return createErrorResult(`File does not exist: ${fullPath}`, {
|
|
50
|
+
filePath: fullPath,
|
|
51
|
+
})
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
fs.writeFileSync(fullPath, content)
|
|
@@ -61,7 +63,9 @@ async function readFile(filePath) {
|
|
|
61
63
|
const fullPath = path.resolve(process.cwd(), filePath)
|
|
62
64
|
|
|
63
65
|
if (!fs.existsSync(fullPath)) {
|
|
64
|
-
return createErrorResult(`File does not exist: ${fullPath}`, {
|
|
66
|
+
return createErrorResult(`File does not exist: ${fullPath}`, {
|
|
67
|
+
filePath: fullPath,
|
|
68
|
+
})
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
const content = fs.readFileSync(fullPath, 'utf8')
|
|
@@ -101,7 +105,9 @@ async function replaceFileText(
|
|
|
101
105
|
if (!modifyResult.success) {
|
|
102
106
|
return modifyResult
|
|
103
107
|
}
|
|
104
|
-
return createSuccessResult({
|
|
108
|
+
return createSuccessResult({
|
|
109
|
+
filePath: path.resolve(process.cwd(), filePath),
|
|
110
|
+
})
|
|
105
111
|
} catch (error) {
|
|
106
112
|
return createErrorResult(error, { filePath })
|
|
107
113
|
}
|
|
@@ -112,7 +118,9 @@ async function appendToFile(filePath, content) {
|
|
|
112
118
|
const fullPath = path.resolve(process.cwd(), filePath)
|
|
113
119
|
|
|
114
120
|
if (!fs.existsSync(fullPath)) {
|
|
115
|
-
return createErrorResult(`File does not exist: ${fullPath}`, {
|
|
121
|
+
return createErrorResult(`File does not exist: ${fullPath}`, {
|
|
122
|
+
filePath: fullPath,
|
|
123
|
+
})
|
|
116
124
|
}
|
|
117
125
|
|
|
118
126
|
fs.appendFileSync(fullPath, content)
|
|
@@ -125,7 +133,10 @@ async function appendToFile(filePath, content) {
|
|
|
125
133
|
function fileExists(filePath) {
|
|
126
134
|
try {
|
|
127
135
|
const fullPath = path.resolve(process.cwd(), filePath)
|
|
128
|
-
return createSuccessResult({
|
|
136
|
+
return createSuccessResult({
|
|
137
|
+
filePath: fullPath,
|
|
138
|
+
exists: fs.existsSync(fullPath),
|
|
139
|
+
})
|
|
129
140
|
} catch (error) {
|
|
130
141
|
return createErrorResult(error, { filePath })
|
|
131
142
|
}
|
|
@@ -197,12 +208,18 @@ async function copyFile(sourcePath, destinationPath) {
|
|
|
197
208
|
|
|
198
209
|
if (fs.existsSync(fullSourcePath)) {
|
|
199
210
|
fs.copyFileSync(fullSourcePath, fullDestPath)
|
|
200
|
-
return createSuccessResult({
|
|
201
|
-
} else {
|
|
202
|
-
return createErrorResult(`Source file does not exist: ${fullSourcePath}`, {
|
|
211
|
+
return createSuccessResult({
|
|
203
212
|
sourcePath: fullSourcePath,
|
|
204
213
|
destinationPath: fullDestPath,
|
|
205
214
|
})
|
|
215
|
+
} else {
|
|
216
|
+
return createErrorResult(
|
|
217
|
+
`Source file does not exist: ${fullSourcePath}`,
|
|
218
|
+
{
|
|
219
|
+
sourcePath: fullSourcePath,
|
|
220
|
+
destinationPath: fullDestPath,
|
|
221
|
+
},
|
|
222
|
+
)
|
|
206
223
|
}
|
|
207
224
|
} catch (error) {
|
|
208
225
|
return createErrorResult(error, { sourcePath, destinationPath })
|
|
@@ -221,7 +238,10 @@ async function moveFile(sourcePath, destinationPath) {
|
|
|
221
238
|
|
|
222
239
|
if (fs.existsSync(fullSourcePath)) {
|
|
223
240
|
fs.renameSync(fullSourcePath, fullDestPath)
|
|
224
|
-
return createSuccessResult({
|
|
241
|
+
return createSuccessResult({
|
|
242
|
+
sourcePath: fullSourcePath,
|
|
243
|
+
destinationPath: fullDestPath,
|
|
244
|
+
})
|
|
225
245
|
}
|
|
226
246
|
return createErrorResult(`Source file does not exist: ${fullSourcePath}`, {
|
|
227
247
|
sourcePath: fullSourcePath,
|
|
@@ -237,7 +257,9 @@ async function getFileInfo(filePath) {
|
|
|
237
257
|
const fullPath = path.resolve(process.cwd(), filePath)
|
|
238
258
|
|
|
239
259
|
if (!fs.existsSync(fullPath)) {
|
|
240
|
-
return createErrorResult(`File does not exist: ${fullPath}`, {
|
|
260
|
+
return createErrorResult(`File does not exist: ${fullPath}`, {
|
|
261
|
+
filePath: fullPath,
|
|
262
|
+
})
|
|
241
263
|
}
|
|
242
264
|
|
|
243
265
|
const stats = fs.statSync(fullPath)
|
|
@@ -259,9 +281,12 @@ async function getFileNameList(dirPath) {
|
|
|
259
281
|
try {
|
|
260
282
|
const fullPath = path.resolve(process.cwd(), dirPath)
|
|
261
283
|
if (!fs.existsSync(fullPath) || !fs.statSync(fullPath).isDirectory()) {
|
|
262
|
-
return createErrorResult(
|
|
263
|
-
|
|
264
|
-
|
|
284
|
+
return createErrorResult(
|
|
285
|
+
`Directory does not exist or is not a directory: ${fullPath}`,
|
|
286
|
+
{
|
|
287
|
+
dirPath: fullPath,
|
|
288
|
+
},
|
|
289
|
+
)
|
|
265
290
|
}
|
|
266
291
|
const files = fs.readdirSync(fullPath)
|
|
267
292
|
return createSuccessResult({ dirPath: fullPath, files })
|
|
@@ -275,11 +300,15 @@ async function clearDirectory(dirPath) {
|
|
|
275
300
|
const fullPath = path.resolve(process.cwd(), dirPath)
|
|
276
301
|
|
|
277
302
|
if (!fs.existsSync(fullPath)) {
|
|
278
|
-
return createErrorResult(`Directory does not exist: ${fullPath}`, {
|
|
303
|
+
return createErrorResult(`Directory does not exist: ${fullPath}`, {
|
|
304
|
+
dirPath: fullPath,
|
|
305
|
+
})
|
|
279
306
|
}
|
|
280
307
|
|
|
281
308
|
if (!fs.statSync(fullPath).isDirectory()) {
|
|
282
|
-
return createErrorResult(`Path is not a directory: ${fullPath}`, {
|
|
309
|
+
return createErrorResult(`Path is not a directory: ${fullPath}`, {
|
|
310
|
+
dirPath: fullPath,
|
|
311
|
+
})
|
|
283
312
|
}
|
|
284
313
|
|
|
285
314
|
const files = fs.readdirSync(fullPath)
|
|
@@ -323,7 +352,10 @@ async function compressToZip(inputPath, outputZipPath) {
|
|
|
323
352
|
}
|
|
324
353
|
// 写入 zip 文件
|
|
325
354
|
await zip.writeZipPromise(absoluteOutput)
|
|
326
|
-
return createSuccessResult({
|
|
355
|
+
return createSuccessResult({
|
|
356
|
+
inputPath: absoluteInput,
|
|
357
|
+
outputZipPath: absoluteOutput,
|
|
358
|
+
})
|
|
327
359
|
} catch (err) {
|
|
328
360
|
return createErrorResult(err, { inputPath, outputZipPath })
|
|
329
361
|
}
|
|
@@ -345,12 +377,47 @@ async function extractZip(zipFilePath, extractToPath) {
|
|
|
345
377
|
await fs.mkdir(absoluteExtractPath, { recursive: true })
|
|
346
378
|
// 解压所有文件
|
|
347
379
|
zip.extractAllTo(absoluteExtractPath, true)
|
|
348
|
-
return createSuccessResult({
|
|
380
|
+
return createSuccessResult({
|
|
381
|
+
zipFilePath: absoluteZipPath,
|
|
382
|
+
extractToPath: absoluteExtractPath,
|
|
383
|
+
})
|
|
349
384
|
} catch (err) {
|
|
350
385
|
return createErrorResult(err, { zipFilePath, extractToPath })
|
|
351
386
|
}
|
|
352
387
|
}
|
|
353
388
|
|
|
389
|
+
// 文档提取功能,提取文件相关内容
|
|
390
|
+
async function extractFileContent(filePrompt, filePathList) {
|
|
391
|
+
try {
|
|
392
|
+
let result = []
|
|
393
|
+
for (const filePath of filePathList) {
|
|
394
|
+
const absolutePath = path.resolve(process.cwd(), filePath)
|
|
395
|
+
const fileName = path.basename(absolutePath)
|
|
396
|
+
if (!fs.existsSync(absolutePath) || !fs.statSync(absolutePath).isFile()) {
|
|
397
|
+
result.push({
|
|
398
|
+
filePath: absolutePath,
|
|
399
|
+
fileName,
|
|
400
|
+
errorContent: `File does not exist or is not a file: ${absolutePath}`,
|
|
401
|
+
})
|
|
402
|
+
}
|
|
403
|
+
const successContent = await this.Tools.createSubAgent(
|
|
404
|
+
`你是文件内容提取助手。请从文件 ${fileName}(路径:${absolutePath})中提取与“${filePrompt}”相关的内容。
|
|
405
|
+
要求:
|
|
406
|
+
1. 只返回与该主题直接相关的原文片段,保持原始语言与措辞。
|
|
407
|
+
2. 不要输出解释、总结、前后缀、Markdown 标记或任何额外说明。
|
|
408
|
+
3. 如果没有相关内容,只返回:null。`,
|
|
409
|
+
)
|
|
410
|
+
return createSuccessResult({
|
|
411
|
+
filePath: absolutePath,
|
|
412
|
+
fileName,
|
|
413
|
+
successContent,
|
|
414
|
+
})
|
|
415
|
+
}
|
|
416
|
+
} catch (error) {
|
|
417
|
+
return createErrorResult(error, null)
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
354
421
|
const descriptions = [
|
|
355
422
|
{
|
|
356
423
|
type: 'function',
|
|
@@ -419,7 +486,8 @@ const descriptions = [
|
|
|
419
486
|
type: 'function',
|
|
420
487
|
function: {
|
|
421
488
|
name: 'fileExists',
|
|
422
|
-
description:
|
|
489
|
+
description:
|
|
490
|
+
'检查指定文件是否存在。参数:filePath 为待检查的文件路径。返回值:对象,包含 success、data(含 exists 布尔值)、error。',
|
|
423
491
|
parameters: {
|
|
424
492
|
type: 'object',
|
|
425
493
|
properties: {
|
|
@@ -642,6 +710,29 @@ const descriptions = [
|
|
|
642
710
|
},
|
|
643
711
|
},
|
|
644
712
|
},
|
|
713
|
+
{
|
|
714
|
+
type: 'function',
|
|
715
|
+
function: {
|
|
716
|
+
name: 'extractFileContent',
|
|
717
|
+
description:
|
|
718
|
+
'根据给定提示词从文件列表中提取相关内容。参数:filePrompt 为提取主题;filePathList 为待提取的文件路径数组。返回值:对象,包含 success、data(含 filePath、fileName、successContent)或 error。',
|
|
719
|
+
parameters: {
|
|
720
|
+
type: 'object',
|
|
721
|
+
properties: {
|
|
722
|
+
filePrompt: {
|
|
723
|
+
type: 'string',
|
|
724
|
+
description: '需要提取的主题或关键描述。',
|
|
725
|
+
},
|
|
726
|
+
filePathList: {
|
|
727
|
+
type: 'array',
|
|
728
|
+
items: { type: 'string' },
|
|
729
|
+
description: '待提取内容的文件路径数组。',
|
|
730
|
+
},
|
|
731
|
+
},
|
|
732
|
+
required: ['filePrompt', 'filePathList'],
|
|
733
|
+
},
|
|
734
|
+
},
|
|
735
|
+
},
|
|
645
736
|
]
|
|
646
737
|
|
|
647
738
|
const functions = {
|
|
@@ -661,7 +752,8 @@ const functions = {
|
|
|
661
752
|
clearDirectory,
|
|
662
753
|
compressToZip,
|
|
663
754
|
extractZip,
|
|
664
|
-
copyFile
|
|
755
|
+
copyFile,
|
|
756
|
+
extractFileContent,
|
|
665
757
|
}
|
|
666
758
|
|
|
667
759
|
const FileTool = {
|
|
@@ -670,7 +762,7 @@ const FileTool = {
|
|
|
670
762
|
'提供文件和目录的创建、读取、修改、删除、移动、重命名、信息获取等文件系统操作功能',
|
|
671
763
|
descriptions,
|
|
672
764
|
functions,
|
|
673
|
-
isSystem: true
|
|
765
|
+
isSystem: true,
|
|
674
766
|
}
|
|
675
767
|
|
|
676
768
|
module.exports = FileTool
|
|
@@ -84,7 +84,7 @@ async function getGenerateSkillRules(goal) {
|
|
|
84
84
|
- README_CN.md(中文说明文档)
|
|
85
85
|
- README.md(英文说明文档)
|
|
86
86
|
|
|
87
|
-
###
|
|
87
|
+
### 第二步:工具函数开发规则
|
|
88
88
|
#### 2.1 核心输出要求
|
|
89
89
|
文件需输出四个核心字段,且代码逻辑清晰、可运行:
|
|
90
90
|
- name:字符串类型,扩展的名称标识
|
|
@@ -102,9 +102,9 @@ async function getGenerateSkillRules(goal) {
|
|
|
102
102
|
- this.Tools.requestAI(systemDescription, prompt, temperature)
|
|
103
103
|
- this.Tools.executeCommand(command)
|
|
104
104
|
4. 函数数量:至少包含1个可被AI工作流调用的函数
|
|
105
|
-
5.
|
|
106
|
-
6. 对于大于
|
|
107
|
-
7.
|
|
105
|
+
5. 对于大于3个函数拆分成多个文件,保持文件结构清晰
|
|
106
|
+
6. 对于大于3个函数的扩展功能,需要在functions中输出一个说明函数,只需返回一个markdown类型的英文字符串,专门用于解释当前扩展工具的使用方法、参数说明、示例等内容,函数名称为「readme」,如「systemFileManagement_readme」;函数描述需要强调调用该扩展模块前必须先阅读该规则文档。
|
|
107
|
+
7. 仅输出代码,不需要测试。
|
|
108
108
|
|
|
109
109
|
#### 2.3 基础代码模板(必须遵循)
|
|
110
110
|
const descriptions = []
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
const path = require('path')
|
|
11
11
|
const fs = require('fs-extra')
|
|
12
|
+
const dayjs = require('dayjs')
|
|
12
13
|
const iconv = require('iconv-lite')
|
|
13
14
|
const { spawnSync } = require('child_process')
|
|
14
15
|
const { detectEncoding } = require('../utils/normal.js')
|
|
@@ -126,6 +127,13 @@ async function executeJSCode(code) {
|
|
|
126
127
|
}
|
|
127
128
|
}
|
|
128
129
|
|
|
130
|
+
// 获取当前系统时间
|
|
131
|
+
function getCurrentTime() {
|
|
132
|
+
const now = dayjs()
|
|
133
|
+
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || 'unknown'
|
|
134
|
+
return `Current system time: ${now.format('YYYY-MM-DD HH:mm:ss')} | ISO: ${now.toISOString()} | Timezone: ${timezone}`
|
|
135
|
+
}
|
|
136
|
+
|
|
129
137
|
// 了解自己
|
|
130
138
|
function getSelfInfo() {
|
|
131
139
|
// 返回自己的代码路径、package.json路径、readme路径等基本信息,供AI有选择的了解自己,回答用户的问题
|
|
@@ -208,6 +216,19 @@ const descriptions = [
|
|
|
208
216
|
},
|
|
209
217
|
},
|
|
210
218
|
},
|
|
219
|
+
{
|
|
220
|
+
type: 'function',
|
|
221
|
+
function: {
|
|
222
|
+
name: 'getCurrentTime',
|
|
223
|
+
description:
|
|
224
|
+
'获取当前系统时间,返回本地时间、ISO时间和时区信息。适用于需要在任务中使用当前时间戳或进行时间记录的场景。',
|
|
225
|
+
parameters: {
|
|
226
|
+
type: 'object',
|
|
227
|
+
properties: {},
|
|
228
|
+
required: [],
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
},
|
|
211
232
|
{
|
|
212
233
|
type: 'function',
|
|
213
234
|
function: {
|
|
@@ -226,6 +247,7 @@ const functions = {
|
|
|
226
247
|
executeCommand,
|
|
227
248
|
requestAI,
|
|
228
249
|
executeJSCode,
|
|
250
|
+
getCurrentTime,
|
|
229
251
|
getSelfInfo,
|
|
230
252
|
}
|
|
231
253
|
|
package/src/cli/index.js
CHANGED