deepfish-ai 1.0.13 → 1.0.15

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.
@@ -1,759 +0,0 @@
1
- /**
2
- * @Author: Roman 306863030@qq.com
3
- * @Date: 2026-03-17 11:59:19
4
- * @LastEditors: Roman 306863030@qq.com
5
- * @LastEditTime: 2026-03-20 16:52:45
6
- * @FilePath: \deepfish\src\core\extension\DefaultExtension.js
7
- * @Description: 默认扩展函数
8
- * @
9
- */
10
- const path = require("path");
11
- const { logError, logSuccess, logInfo, getConfigPath } = require("../utils/log");
12
- const fs = require("fs-extra");
13
- const shelljs = require("shelljs");
14
- const iconv = require("iconv-lite"); // 用于编码转换
15
- const os = require("os"); // 用于判断系统类型
16
- const { cloneDeep } = require("lodash");
17
- const { aiRequestSingle } = require("../ai-services/AiWorker/AiTools");
18
-
19
- // 执行系统命令
20
- // 执行系统命令(全平台兼容:Windows/PowerShell/CentOS)
21
- async function executeCommand(command) {
22
- return new Promise((resolve, reject) => {
23
- logSuccess(`Executing system command: ${command}`);
24
- const platform = os.platform();
25
- const targetEncoding = platform === "win32" ? "gbk" : "utf-8"; // Windows(含PowerShell)用gbk,Linux/macOS用utf-8
26
- shelljs.exec(
27
- command,
28
- {
29
- async: true,
30
- cwd: process.cwd(),
31
- encoding: "binary",
32
- silent: true,
33
- },
34
- (code, stdout, stderr) => {
35
- try {
36
- let stdoutUtf8 = iconv.decode(
37
- Buffer.from(stdout, "binary"),
38
- targetEncoding,
39
- );
40
- const stderrUtf8 = iconv.decode(
41
- Buffer.from(stderr, "binary"),
42
- targetEncoding,
43
- );
44
- if (stderrUtf8 && !stderrUtf8.trim().startsWith("WARNING")) {
45
- // 过滤无关警告
46
- const error = new Error(
47
- `Command failed (code ${code}): ${stderrUtf8}`,
48
- );
49
- logError(`Execute error: ${error.message}`);
50
- reject(error);
51
- return;
52
- }
53
- if (stdoutUtf8 === "undefined") {
54
- stdoutUtf8 = "";
55
- }
56
- logSuccess(`${stdoutUtf8} \n Command executed successfully`);
57
- resolve(stdoutUtf8 || "Command executed successfully");
58
- } catch (decodeError) {
59
- logError(`Encoding convert error: ${decodeError.message}`);
60
- reject(
61
- new Error(`Failed to parse command output: ${decodeError.message}`),
62
- );
63
- }
64
- },
65
- );
66
- });
67
- }
68
-
69
- // 请求ai服务
70
- async function requestAI(
71
- systemDescription,
72
- prompt,
73
- temperature = this.aiConfig.temperature,
74
- ) {
75
- logSuccess(`Requesting AI`);
76
- if (
77
- typeof systemDescription === "object" &&
78
- systemDescription.systemDescription
79
- ) {
80
- prompt = systemDescription.prompt || prompt || "";
81
- systemDescription = systemDescription.systemDescription || "";
82
- }
83
- try {
84
- logInfo(`aiSystem: ${systemDescription}`);
85
- logInfo(`aiPrompt: ${prompt}`);
86
- let aiConfig = this.aiConfig;
87
- if (temperature !== aiConfig.temperature) {
88
- aiConfig = cloneDeep(aiConfig);
89
- aiConfig.temperature = temperature;
90
- }
91
- const response = await aiRequestSingle(
92
- this.aiService.client,
93
- aiConfig,
94
- systemDescription,
95
- prompt,
96
- );
97
- logInfo(`aiResponse: ${response}`);
98
- return response;
99
- } catch (error) {
100
- logError(`Error executing AI function: ${error.message}`);
101
- throw error;
102
- }
103
- }
104
-
105
- // 执行js代码
106
- async function executeJSCode(code) {
107
- logSuccess("Executing JavaScript code: ");
108
- logSuccess(code);
109
-
110
- try {
111
- const { functions } = this.extensionManager.extensions;
112
- const Func = new Function(
113
- "Tools",
114
- "require",
115
- `return (async () => {
116
- this.logMessages = []
117
- const originalLog = console.log
118
- const newLog = function () {
119
- originalLog.apply(console, arguments)
120
- this.logMessages.push(Array.from(arguments).join(' '))
121
- }
122
- console.log = newLog.bind(this)
123
- ${code}
124
- console.log = originalLog
125
- return this.logMessages.join('\\n')
126
- })()`,
127
- );
128
- const originalRequire = require;
129
- const newRequire = (modulePath) => {
130
- if (modulePath.startsWith("./")) {
131
- const resolvedPath = path.resolve(".", modulePath);
132
- return originalRequire(resolvedPath);
133
- }
134
- return originalRequire(modulePath);
135
- };
136
-
137
- const result = await Func(functions, newRequire);
138
-
139
- return result || "";
140
- } catch (error) {
141
- logError(`Error executing code: ${error.stack}`);
142
- throw error;
143
- }
144
- }
145
- // 生成一个扩展函数文件 关键字:内置函数、扩展工具
146
- async function getExtensionFileRule(goal) {
147
- const newGoal = `
148
- ### 任务目标
149
- 基于指定规则创建一个标准化的Node.js NPM项目,实现用户目标:${goal},最终输出符合AI工作流调用规范的函数模块,并配套中英文说明文档。
150
-
151
- ### 第一步:项目初始化
152
- 1. 目录创建:新建目录,目录名称为「项目功能名称」,作为NPM项目根目录
153
- 2. package.json配置:
154
- - name字段值:@deepfish-ai/项目功能名称(替换「项目功能名称」为实际功能名)
155
- - git仓库地址:固定为 https://github.com/qq306863030/deepfish-extensions.git
156
- - author设置为"DeepFish AI",
157
- 3. 主文件:项目入口文件必须命名为index.js
158
- 4. 文档文件:项目根目录需新增2个文档文件:
159
- - README_CN.md(中文说明文档)
160
- - README.md(英文说明文档)
161
-
162
- ### 第二步:index.js 完整开发规范
163
- #### 2.1 核心输出要求
164
- 文件需输出两个核心字段,且代码逻辑清晰、可运行:
165
- - descriptions:数组类型,每个元素为OpenAI可识别的函数描述对象
166
- - functions:对象类型,key为函数名称,value为函数方法体
167
-
168
- #### 2.2 开发强制规则
169
- 1. 参数一致性:functions中函数的入参,必须与descriptions中对应函数声明的parameters完全一致
170
- 2. 命名规范:
171
- - 函数名称前缀:「领域用途+分隔符」(如systemFileManagement_)
172
- - 函数描述开头:统一格式「领域用途+分隔符+功能描述」(如系统文件管理:重命名文件)
173
- 3. 内置工具调用:函数内部可直接使用this.Tools下的内置方法,示例:
174
- - this.Tools.requestAI(systemDescription, prompt, temperature)
175
- - this.Tools.readFile(filePath)
176
- - 其他文件处理类内置函数(运行时自动注入)
177
- 4. 函数数量:至少包含1个可被AI工作流调用的函数
178
-
179
- #### 2.3 基础代码模板(必须遵循)
180
- const descriptions = []
181
- const functions = {}
182
- module.exports = {
183
- descriptions,
184
- functions,
185
- }
186
-
187
- #### 2.4 参考示例(可参考格式)
188
- const descriptions = [
189
- {
190
- name: 'systemFileManagement_renameFile',
191
- description: '系统文件管理:重命名文件',
192
- parameters: {
193
- type: 'object',
194
- properties: {
195
- oldPath: { type: 'string', description: '旧文件路径' },
196
- newPath: { type: 'string', description: '新文件路径' },
197
- },
198
- },
199
- },
200
- ]
201
- const functions = {
202
- systemFileManagement_renameFile: (oldPath, newPath) => {
203
- return this.Tools.rename(oldPath, newPath)
204
- },
205
- }
206
- module.exports = {
207
- descriptions,
208
- functions,
209
- }
210
-
211
- ### 第三步:README文档规范
212
- #### 3.1 通用要求
213
- - 两个文档需在标题下方包含「中英文切换标签」(如文档顶部标注「English | 中文」/「中文 | English」)
214
- - 结构保持一致,仅语言不同,核心模块顺序不可调整
215
- - 文件名称README_CN.md(中文)、README.md(英文)
216
- - 链接使用相对路径,如[中文](./README_CN.md)
217
-
218
- #### 3.2 核心模块
219
- 1. 总体功能描述:
220
- - 清晰说明当前NPM包的核心定位、整体功能价值、适用场景
221
- - 语言简洁易懂,无需技术细节,聚焦「做什么」而非「怎么做」
222
- 2. 快速开始:
223
- - 明确说明安装步骤,顺序不可颠倒:
224
- ① 先安装deepfish-ai全局库:npm install deepfish-ai -g
225
- ② 再安装当前项目库:npm install @deepfish-ai/项目功能名称 -g
226
- 3. 函数列表及功能描述:
227
- - 列出当前项目中所有函数名称
228
- - 对应说明每个函数的核心功能
229
- - 无需编写各个函数的具体使用方法
230
- `;
231
- return newGoal;
232
- }
233
-
234
- // 获取ai的配置
235
- function getAiConfig() {
236
- return cloneDeep(this.aiConfig);
237
- }
238
-
239
- // 获取ai的配置文件所在目录
240
- function getAiConfigPath() {
241
- return getConfigPath();
242
- }
243
-
244
- async function createFile(filePath, content) {
245
- try {
246
- const fullPath = path.resolve(process.cwd(), filePath);
247
- const dirPath = path.dirname(fullPath);
248
-
249
- if (!fs.existsSync(dirPath)) {
250
- fs.mkdirSync(dirPath, { recursive: true });
251
- }
252
- fs.writeFileSync(fullPath, content);
253
- return true;
254
- } catch (error) {
255
- return false;
256
- }
257
- }
258
-
259
- async function modifyFile(filePath, content) {
260
- try {
261
- const fullPath = path.resolve(process.cwd(), filePath);
262
-
263
- if (!fs.existsSync(fullPath)) {
264
- return false;
265
- }
266
-
267
- fs.writeFileSync(fullPath, content);
268
- return true;
269
- } catch (error) {
270
- return false;
271
- }
272
- }
273
-
274
- async function readFile(filePath) {
275
- try {
276
- const fullPath = path.resolve(process.cwd(), filePath);
277
-
278
- if (!fs.existsSync(fullPath)) {
279
- return null;
280
- }
281
-
282
- const content = fs.readFileSync(fullPath, "utf8");
283
- return content;
284
- } catch (error) {
285
- return null;
286
- }
287
- }
288
-
289
- async function appendToFile(filePath, content) {
290
- try {
291
- const fullPath = path.resolve(process.cwd(), filePath);
292
-
293
- if (!fs.existsSync(fullPath)) {
294
- return false;
295
- }
296
-
297
- fs.appendFileSync(fullPath, content);
298
- return true;
299
- } catch (error) {
300
- return false;
301
- }
302
- }
303
-
304
- function fileExists(filePath) {
305
- const fullPath = path.resolve(process.cwd(), filePath);
306
- return fs.existsSync(fullPath);
307
- }
308
-
309
- async function createDirectory(dirPath) {
310
- try {
311
- const fullPath = path.resolve(process.cwd(), dirPath);
312
- if (!fs.existsSync(fullPath)) {
313
- fs.mkdirSync(fullPath, { recursive: true });
314
- }
315
- return true;
316
- } catch (error) {
317
- return false;
318
- }
319
- }
320
-
321
- async function deleteFile(filePath) {
322
- try {
323
- const fullPath = path.resolve(process.cwd(), filePath);
324
-
325
- if (fs.existsSync(fullPath)) {
326
- fs.unlinkSync(fullPath);
327
- }
328
- return true;
329
- } catch (error) {
330
- return false;
331
- }
332
- }
333
-
334
- async function deleteDirectory(dirPath) {
335
- try {
336
- const fullPath = path.resolve(process.cwd(), dirPath);
337
-
338
- if (fs.existsSync(fullPath)) {
339
- fs.rmSync(fullPath, { recursive: true, force: true });
340
- }
341
- return true;
342
- } catch (error) {
343
- return false;
344
- }
345
- }
346
-
347
- async function rename(oldPath, newPath) {
348
- try {
349
- const fullOldPath = path.resolve(process.cwd(), oldPath);
350
- const fullNewPath = path.resolve(process.cwd(), newPath);
351
-
352
- if (fs.existsSync(fullOldPath)) {
353
- fs.renameSync(fullOldPath, fullNewPath);
354
- }
355
- return true;
356
- } catch (error) {
357
- return false;
358
- }
359
- }
360
-
361
- async function moveFile(sourcePath, destinationPath) {
362
- try {
363
- const fullSourcePath = path.resolve(process.cwd(), sourcePath);
364
- const fullDestPath = path.resolve(process.cwd(), destinationPath);
365
- const destDirPath = path.dirname(fullDestPath);
366
-
367
- if (!fs.existsSync(destDirPath)) {
368
- fs.mkdirSync(destDirPath, { recursive: true });
369
- }
370
-
371
- if (fs.existsSync(fullSourcePath)) {
372
- fs.renameSync(fullSourcePath, fullDestPath);
373
- }
374
- return true;
375
- } catch (error) {
376
- return false;
377
- }
378
- }
379
-
380
- async function getFileInfo(filePath) {
381
- try {
382
- const fullPath = path.resolve(process.cwd(), filePath);
383
-
384
- if (!fs.existsSync(fullPath)) {
385
- return null;
386
- }
387
-
388
- const stats = fs.statSync(fullPath);
389
- return {
390
- path: fullPath,
391
- size: stats.size,
392
- birthtime: stats.birthtime,
393
- mtime: stats.mtime,
394
- ctime: stats.ctime,
395
- isFile: stats.isFile(),
396
- isDirectory: stats.isDirectory(),
397
- };
398
- } catch (error) {
399
- return null;
400
- }
401
- }
402
-
403
- async function getFileNameList(dirPath) {
404
- try {
405
- const fullPath = path.resolve(process.cwd(), dirPath);
406
- if (!fs.existsSync(fullPath) || !fs.statSync(fullPath).isDirectory()) {
407
- return [];
408
- }
409
- const files = fs
410
- .readdirSync(fullPath)
411
- .filter((file) => file !== "ai-history" && file !== "ai-log");
412
- return files;
413
- } catch (error) {
414
- return [];
415
- }
416
- }
417
-
418
- async function clearDirectory(dirPath) {
419
- try {
420
- const fullPath = path.resolve(process.cwd(), dirPath);
421
-
422
- if (!fs.existsSync(fullPath)) {
423
- return false;
424
- }
425
-
426
- if (!fs.statSync(fullPath).isDirectory()) {
427
- return false;
428
- }
429
-
430
- const files = fs.readdirSync(fullPath);
431
-
432
- for (const file of files) {
433
- const filePath = path.join(fullPath, file);
434
- if (fs.statSync(filePath).isDirectory()) {
435
- fs.rmSync(filePath, { recursive: true, force: true });
436
- } else {
437
- fs.unlinkSync(filePath);
438
- }
439
- }
440
-
441
- return true;
442
- } catch (error) {
443
- return false;
444
- }
445
- }
446
-
447
- const descriptions = [
448
- {
449
- type: "function",
450
- function: {
451
- name: "executeCommand",
452
- description:
453
- '执行系统命令,返回执行结果。适用于运行shell命令、系统工具等。命令执行失败时会抛出错误,成功时返回命令执行结果字符串或"System command executed successfully"。',
454
- parameters: {
455
- type: "object",
456
- properties: {
457
- command: { type: "string" },
458
- },
459
- required: ["command"],
460
- },
461
- },
462
- },
463
- {
464
- type: "function",
465
- function: {
466
- name: "requestAI",
467
- description:
468
- "请求AI服务处理简单任务,如随机生成一段话、翻译文本、数学计算、代码分析、知识检索等。通过systemDescription参数指定AI的行为和限制,prompt参数输入任务描述, temperature参数指定AI的温度(0-2之间的浮点数,默认为用户配置)。返回AI处理后的结果字符串,执行失败时会抛出错误。",
469
- parameters: {
470
- type: "object",
471
- properties: {
472
- systemDescription: { type: "string" },
473
- prompt: { type: "string" },
474
- temperature: { type: "number" },
475
- },
476
- required: ["systemDescription", "prompt"],
477
- },
478
- },
479
- },
480
- {
481
- type: "function",
482
- function: {
483
- name: "executeJSCode",
484
- description:
485
- '执行JavaScript代码,返回代码执行结果。代码中可通过Tools命名空间直接调用其他工具函数(如await Tools.createFile(),注意:不需要使用require引入),Tools中引入了一些常用库可直接调用(Tools.fs="fs-extra", Tools.dayjs="dayjs", Tools.axios="axios", Tools.lodash="lodash"),支持引入自定义模块(需使用绝对路径)。注意:1.代码中不要使用__dirname获取当前目录,请使用path.resolve(".")来获取当前目录。2.执行失败时会抛出错误,成功时返回代码执行结果或空字符串。',
486
- parameters: {
487
- type: "object",
488
- properties: {
489
- code: { type: "string" },
490
- },
491
- required: ["code"],
492
- },
493
- },
494
- },
495
- {
496
- type: "function",
497
- function: {
498
- name: "createFile",
499
- description:
500
- "创建一个包含指定内容的新文件,返回布尔值表示操作是否成功。如果目录不存在会自动创建目录结构。",
501
- parameters: {
502
- type: "object",
503
- properties: {
504
- filePath: { type: "string" },
505
- content: { type: "string" },
506
- },
507
- required: ["filePath", "content"],
508
- },
509
- },
510
- },
511
- {
512
- type: "function",
513
- function: {
514
- name: "modifyFile",
515
- description:
516
- "修改指定文件的内容,返回布尔值表示操作是否成功。如果文件不存在则返回false。",
517
- parameters: {
518
- type: "object",
519
- properties: {
520
- filePath: { type: "string" },
521
- content: { type: "string" },
522
- },
523
- required: ["filePath", "content"],
524
- },
525
- },
526
- },
527
- {
528
- type: "function",
529
- function: {
530
- name: "readFile",
531
- description:
532
- "读取指定文件的内容,返回文件内容字符串。如果文件不存在或读取失败则返回null。",
533
- parameters: {
534
- type: "object",
535
- properties: {
536
- filePath: { type: "string" },
537
- },
538
- required: ["filePath"],
539
- },
540
- },
541
- },
542
- {
543
- type: "function",
544
- function: {
545
- name: "appendToFile",
546
- description:
547
- "向指定文件追加内容,返回布尔值表示操作是否成功。如果文件不存在则返回false。",
548
- parameters: {
549
- type: "object",
550
- properties: {
551
- filePath: { type: "string" },
552
- content: { type: "string" },
553
- },
554
- required: ["filePath", "content"],
555
- },
556
- },
557
- },
558
- {
559
- type: "function",
560
- function: {
561
- name: "fileExists",
562
- description: "检查指定文件是否存在,返回布尔值。",
563
- parameters: {
564
- type: "object",
565
- properties: {
566
- filePath: { type: "string" },
567
- },
568
- required: ["filePath"],
569
- },
570
- },
571
- },
572
- {
573
- type: "function",
574
- function: {
575
- name: "createDirectory",
576
- description:
577
- "创建一个新目录,返回布尔值表示操作是否成功。支持递归创建目录结构。",
578
- parameters: {
579
- type: "object",
580
- properties: {
581
- dirPath: { type: "string" },
582
- },
583
- required: ["dirPath"],
584
- },
585
- },
586
- },
587
- {
588
- type: "function",
589
- function: {
590
- name: "deleteFile",
591
- description:
592
- "删除指定文件,返回布尔值表示操作是否成功。如果文件不存在也会返回true。",
593
- parameters: {
594
- type: "object",
595
- properties: {
596
- filePath: { type: "string" },
597
- },
598
- required: ["filePath"],
599
- },
600
- },
601
- },
602
- {
603
- type: "function",
604
- function: {
605
- name: "deleteDirectory",
606
- description:
607
- "删除指定目录,返回布尔值表示操作是否成功。支持递归删除目录及其内容。如果目录不存在也会返回true。",
608
- parameters: {
609
- type: "object",
610
- properties: {
611
- dirPath: { type: "string" },
612
- },
613
- required: ["dirPath"],
614
- },
615
- },
616
- },
617
- {
618
- type: "function",
619
- function: {
620
- name: "rename",
621
- description:
622
- "重命名文件或目录,返回布尔值表示操作是否成功。如果原文件不存在也会返回true。",
623
- parameters: {
624
- type: "object",
625
- properties: {
626
- oldPath: { type: "string" },
627
- newPath: { type: "string" },
628
- },
629
- required: ["oldPath", "newPath"],
630
- },
631
- },
632
- },
633
- {
634
- type: "function",
635
- function: {
636
- name: "moveFile",
637
- description:
638
- "移动文件,返回布尔值表示操作是否成功。如果目标目录不存在会自动创建。如果源文件不存在也会返回true。",
639
- parameters: {
640
- type: "object",
641
- properties: {
642
- sourcePath: { type: "string" },
643
- destinationPath: { type: "string" },
644
- },
645
- required: ["sourcePath", "destinationPath"],
646
- },
647
- },
648
- },
649
- {
650
- type: "function",
651
- function: {
652
- name: "getFileInfo",
653
- description:
654
- "获取指定文件的信息,返回文件信息对象。如果文件不存在或获取失败则返回null。返回对象包含path、size、birthtime、mtime、ctime、isFile、isDirectory等属性。",
655
- parameters: {
656
- type: "object",
657
- properties: {
658
- filePath: { type: "string" },
659
- },
660
- required: ["filePath"],
661
- },
662
- },
663
- },
664
- {
665
- type: "function",
666
- function: {
667
- name: "getFileNameList",
668
- description:
669
- "获取指定目录下的所有文件名,返回文件名数组。如果目录不存在或不是目录则返回空数组。",
670
- parameters: {
671
- type: "object",
672
- properties: {
673
- dirPath: { type: "string" },
674
- },
675
- required: ["dirPath"],
676
- },
677
- },
678
- },
679
- {
680
- type: "function",
681
- function: {
682
- name: "clearDirectory",
683
- description:
684
- "清空指定目录的内容,返回布尔值表示操作是否成功。如果目录不存在或不是目录则返回false。",
685
- parameters: {
686
- type: "object",
687
- properties: {
688
- dirPath: { type: "string" },
689
- },
690
- required: ["dirPath"],
691
- },
692
- },
693
- },
694
- {
695
- type: "function",
696
- function: {
697
- name: "getExtensionFileRule",
698
- description:
699
- "如果用户需要为本程序ai工作流生成一个或多个工具函数作为一个工作流执行过程中调用的扩展工具,则需要先调用此函数获取生成扩展文件的规则;示例:生成一个扩展工具: 能够产生一个随机数的函数;",
700
- parameters: {
701
- type: "object",
702
- properties: {
703
- goal: { type: "string" },
704
- },
705
- required: ["goal"],
706
- },
707
- },
708
- },
709
- {
710
- type: "function",
711
- function: {
712
- name: "getAiConfig",
713
- description: "获取ai请求接口的配置参数",
714
- parameters: {
715
- type: "object",
716
- properties: {},
717
- required: [],
718
- },
719
- },
720
- },
721
- {
722
- type: "function",
723
- function: {
724
- name: "getAiConfigPath",
725
- description: "获取ai请求接口配置的文件地址",
726
- parameters: {
727
- type: "object",
728
- properties: {},
729
- required: [],
730
- },
731
- },
732
- },
733
- ];
734
- const functions = {
735
- executeCommand,
736
- requestAI,
737
- executeJSCode,
738
- createFile,
739
- modifyFile,
740
- readFile,
741
- appendToFile,
742
- fileExists,
743
- createDirectory,
744
- deleteFile,
745
- deleteDirectory,
746
- rename,
747
- moveFile,
748
- getFileInfo,
749
- getFileNameList,
750
- clearDirectory,
751
- getExtensionFileRule,
752
- getAiConfig,
753
- getAiConfigPath,
754
- };
755
-
756
- module.exports = {
757
- descriptions,
758
- functions,
759
- };