deepfish-ai 1.0.24 → 1.0.25

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_CN.md CHANGED
@@ -378,8 +378,8 @@ AI始终使用相对于当前工作目录的相对路径。
378
378
 
379
379
  ### 对话历史
380
380
 
381
- 对话历史是以程序执行目录为单位创建的,每个程序的执行目录会对应一个独立的 Agent 上下文。这意味着在不同目录下启动的对话是相互独立的。
382
-
381
+ 对话历史是以程序执行目录为单位创建的,每个程序的执行目录会对应一个独立的 Agent 上下文。这意味着在不同目录下启动的对话是相互独立的。
382
+
383
383
  > **⚠️ 重要提示:** AI上下文是以目录为单位的,一个目录对应一个上下文。**请不要在同一个目录下开启两个命令行对话框**,以免造成上下文冲突和意外行为。
384
384
 
385
385
  对话历史会在一定时间内自动清除(通过配置文件中的 `maxMemoryExpireTime` 字段控制,默认为 30 天)。您也可以手动管理对话历史:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepfish-ai",
3
- "version": "1.0.24",
3
+ "version": "1.0.25",
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",
@@ -876,7 +876,33 @@ async function patchDocxText(filePath, replacements) {
876
876
 
877
877
  // ─── 工具描述 ─────────────────────────────────────────────────────────────────
878
878
 
879
+
880
+ // ─── 使用说明 ─────────────────────────────────────────────────────────────────
881
+
882
+ function docxReadme() {
883
+ return `【DOCX 工具使用说明】
884
+ 1. 优先使用本工具内置函数完成任务(读取、创建、搜索、替换、模板填充、格式转换、合并等)。
885
+ 2. 如果内置函数无法满足需求(如复杂排版保真、特殊宏处理、跨格式高级转换),再尝试使用 LibreOffice 命令行。
886
+ 3. 在调用 LibreOffice 前,先检测系统是否已安装 LibreOffice:
887
+ - 已安装:直接使用 LibreOffice 命令行继续处理。
888
+ - 未安装:询问用户是否允许安装。
889
+ 4. 若用户同意安装:引导完成安装后继续执行原任务。
890
+ 5. 若用户拒绝安装:明确告知当前能力限制,并终止该操作。
891
+
892
+ 建议:
893
+ - 常规文档处理优先使用内置函数,速度更快且依赖更少。
894
+ - 仅在确实需要高保真格式转换或复杂排版时才启用 LibreOffice 路径。`
895
+ }
896
+
879
897
  const descriptions = [
898
+ {
899
+ type: 'function',
900
+ function: {
901
+ name: 'docxReadme',
902
+ description: '获取 DOCX 工具集的使用说明, 调用函数前必须先查看本说明。',
903
+ parameters: {},
904
+ }
905
+ },
880
906
  {
881
907
  type: 'function',
882
908
  function: {
@@ -1224,6 +1250,7 @@ const descriptions = [
1224
1250
  // ─── 导出 ──────────────────────────────────────────────────────────────────────
1225
1251
 
1226
1252
  const functions = {
1253
+ docxReadme,
1227
1254
  readDocxText,
1228
1255
  readDocxHtml,
1229
1256
  getDocxInfo,
@@ -1,5 +1,4 @@
1
1
  const path = require('path')
2
- const os = require('os')
3
2
  const fs = require('fs-extra')
4
3
  const crypto = require('crypto')
5
4
  const mammoth = require('mammoth')
@@ -15,25 +14,8 @@ function fail(error, data = null) {
15
14
  return { success: false, error: error?.message || String(error), data }
16
15
  }
17
16
 
18
- // 获取配置地址
19
- function _getConfigFilePath() {
20
- const configDir = path.join(os.homedir(), './.deepfish-ai')
21
- const configPath = path.join(configDir, './config.js')
22
- return configPath
23
- }
24
-
25
- function _loadConfig(configPath) {
26
- fs.ensureDirSync(path.dirname(configPath))
27
- if (!fs.existsSync(configPath)) {
28
- fs.writeFileSync(configPath, 'module.exports = {}')
29
- }
30
- const resolved = require.resolve(configPath)
31
- delete require.cache[resolved]
32
- return require(configPath)
33
- }
34
-
35
- function _getKbRootPath(knowledgeBasePath = '') {
36
- return path.resolve(process.cwd(), knowledgeBasePath || '.deepfish-rag')
17
+ function _getKbRootPath() {
18
+ return path.resolve(process.cwd(), '.deepfish-rag')
37
19
  }
38
20
 
39
21
  function _getKbIndexPath(kbRootPath) {
@@ -95,10 +77,49 @@ async function _readDocumentContent(filePath) {
95
77
  return fs.readFileSync(filePath, 'utf8')
96
78
  }
97
79
 
80
+ function _normalizeText(content = '') {
81
+ return String(content || '').replace(/\s+/g, ' ').trim()
82
+ }
83
+
84
+ function _buildSummary(content = '', maxLen = 320) {
85
+ const normalized = _normalizeText(content)
86
+ if (!normalized) return ''
87
+ if (normalized.length <= maxLen) return normalized
88
+ return `${normalized.slice(0, maxLen)}...`
89
+ }
90
+
91
+ async function _extractSummary(content = '', maxLen = 320, absolutePath = '') {
92
+ const fallbackSummary = _buildSummary(content, maxLen)
93
+ if (!fallbackSummary) return ''
94
+
95
+ if (!this?.Tools?.requestAI) {
96
+ return fallbackSummary
97
+ }
98
+
99
+ const systemDescription = '你是文档摘要助手,只输出简洁摘要正文,不要解释。'
100
+ const prompt = `请为下面文档提取摘要:\n\n文档路径:${absolutePath || '未知'}\n文档内容:\n${content}\n\n要求:\n1. 输出中文摘要,保留关键事实与结论。\n2. 摘要长度不超过${maxLen}个字符。\n3. 不要输出标题、前后缀或解释,只输出摘要正文。`
101
+
102
+ try {
103
+ const aiSummary = await this.Tools.requestAI(systemDescription, prompt, 0.2)
104
+ if (typeof aiSummary !== 'string') {
105
+ return fallbackSummary
106
+ }
107
+ const normalizedSummary = _normalizeText(aiSummary)
108
+ if (!normalizedSummary) {
109
+ return fallbackSummary
110
+ }
111
+ return normalizedSummary.length > maxLen
112
+ ? `${normalizedSummary.slice(0, maxLen)}...`
113
+ : normalizedSummary
114
+ } catch {
115
+ return fallbackSummary
116
+ }
117
+ }
118
+
98
119
  function _getEmptyKnowledgeBase(kbRootPath) {
99
120
  const now = new Date().toISOString()
100
121
  return {
101
- version: 1,
122
+ version: 2,
102
123
  name: 'deepfish-rag',
103
124
  kbRootPath,
104
125
  createdAt: now,
@@ -116,13 +137,30 @@ function _loadKnowledgeBase(kbRootPath) {
116
137
  fs.writeFileSync(indexPath, JSON.stringify(emptyKb, null, 2), 'utf8')
117
138
  return emptyKb
118
139
  }
140
+
119
141
  const content = fs.readFileSync(indexPath, 'utf8')
120
142
  const parsed = JSON.parse(content)
121
- return {
143
+ const base = {
122
144
  ..._getEmptyKnowledgeBase(kbRootPath),
123
145
  ...parsed,
124
146
  kbRootPath,
125
147
  }
148
+
149
+ // 向后兼容旧结构:若旧数据里有content,则在加载时迁移为summary。
150
+ base.documents = (base.documents || []).map((doc) => {
151
+ const absolutePath = path.resolve(doc.absolutePath || doc.sourcePath || '')
152
+ return {
153
+ id: doc.id || _sha256(absolutePath).slice(0, 16),
154
+ absolutePath,
155
+ sourceHash: doc.sourceHash || '',
156
+ size: doc.size || 0,
157
+ summary: doc.summary || _buildSummary(doc.content || ''),
158
+ createdAt: doc.createdAt || base.createdAt,
159
+ updatedAt: doc.updatedAt || base.updatedAt,
160
+ }
161
+ })
162
+
163
+ return base
126
164
  }
127
165
 
128
166
  function _saveKnowledgeBase(kbRootPath, knowledgeBase) {
@@ -131,243 +169,170 @@ function _saveKnowledgeBase(kbRootPath, knowledgeBase) {
131
169
  fs.writeFileSync(indexPath, JSON.stringify(knowledgeBase, null, 2), 'utf8')
132
170
  }
133
171
 
134
- function _chunkText(content = '', chunkSize = 800, overlap = 120) {
135
- const text = String(content || '')
136
- const size = Math.max(200, Number(chunkSize) || 800)
137
- const overlapSize = Math.max(0, Math.min(size - 1, Number(overlap) || 120))
138
- const step = Math.max(1, size - overlapSize)
139
- const chunks = []
140
- for (let i = 0; i < text.length; i += step) {
141
- const chunk = text.slice(i, i + size)
142
- if (!chunk.trim()) continue
143
- chunks.push({
144
- offsetStart: i,
145
- offsetEnd: i + chunk.length,
146
- content: chunk,
147
- })
148
- if (i + size >= text.length) {
149
- break
150
- }
151
- }
152
- return chunks
153
- }
154
-
155
- function _calcKeywordScore(content = '', keyword = '') {
156
- if (!keyword) return 0
157
- const src = String(content || '').toLowerCase()
158
- const kw = String(keyword || '').toLowerCase()
159
- let count = 0
160
- let fromIndex = 0
161
- while (true) {
162
- const idx = src.indexOf(kw, fromIndex)
163
- if (idx < 0) break
164
- count += 1
165
- fromIndex = idx + kw.length
172
+ async function _upsertKnowledgeBase(sourcePath = '', knowledgeBasePath = '', reset = false) {
173
+ const inputSourcePath = sourcePath || (await aiInquirer.askInput('请输入源文件目录或文件路径', '', {}))
174
+ if (!inputSourcePath) {
175
+ return fail('未提供源文件目录或文件路径')
166
176
  }
167
- return count
168
- }
169
177
 
170
- // 获取向量化配置
171
- async function getEmbeddingConfig() {
172
- const configPath = _getConfigFilePath()
173
- const config = _loadConfig(configPath)
174
- if (!config.EMBEDDING_API) {
175
- // 提示用户输入
176
- const res = await aiInquirer.askInput('请输入向量化接口地址', '', {})
177
- if (res) {
178
- config.EMBEDDING_API = res
179
- setEmbeddingConfig(config.EMBEDDING_API, config.EMBEDDING_API_KEY)
180
- }
181
- }
182
- if (!config.EMBEDDING_API_KEY) {
183
- // 提示用户输入
184
- const res = await aiInquirer.askInput('请输入向量化接口密钥', '', {})
185
- if (res) {
186
- config.EMBEDDING_API_KEY = res
187
- setEmbeddingConfig(config.EMBEDDING_API, config.EMBEDDING_API_KEY)
188
- }
189
- }
190
- return {
191
- EMBEDDING_API: config.EMBEDDING_API || '',
192
- EMBEDDING_API_KEY: config.EMBEDDING_API_KEY || '',
178
+ const resolvedSourcePath = path.resolve(process.cwd(), inputSourcePath)
179
+ if (!fs.existsSync(resolvedSourcePath)) {
180
+ return fail(`Source path does not exist: ${resolvedSourcePath}`, {
181
+ sourcePath: resolvedSourcePath,
182
+ })
193
183
  }
194
- }
195
184
 
196
- // 写入向量化配置
197
- function setEmbeddingConfig(embeddingApi, embeddingApiKey) {
198
- const configPath = _getConfigFilePath()
199
- const config = _loadConfig(configPath)
200
- const newConfig = {
201
- ...config,
202
- EMBEDDING_API: embeddingApi,
203
- EMBEDDING_API_KEY: embeddingApiKey,
185
+ const kbRootPath = _getKbRootPath(knowledgeBasePath)
186
+ if (reset && fs.existsSync(kbRootPath)) {
187
+ fs.removeSync(kbRootPath)
204
188
  }
205
- fs.writeFileSync(configPath, `module.exports = ${JSON.stringify(newConfig, null, 2)}`)
206
- return ok({
207
- configPath,
208
- EMBEDDING_API: embeddingApi || '',
209
- EMBEDDING_API_KEY: embeddingApiKey || '',
210
- })
211
- }
212
189
 
213
- // 创建/续加知识库,默认路径为命令执行目录下 .deepfish-rag
214
- async function buildKnowledgeBase(sourcePath = '', knowledgeBasePath = '') {
215
- try {
216
- const inputSourcePath = sourcePath || (await aiInquirer.askInput('请输入源文件目录或文件路径', '', {}))
217
- if (!inputSourcePath) {
218
- return fail('未提供源文件目录或文件路径')
219
- }
190
+ const knowledgeBase = _loadKnowledgeBase(kbRootPath)
191
+ const sourceFiles = _collectSourceFiles(resolvedSourcePath)
192
+ const supportedFiles = sourceFiles.filter((filePath) => _isSupportedFile(filePath))
220
193
 
221
- const resolvedSourcePath = path.resolve(process.cwd(), inputSourcePath)
222
- if (!fs.existsSync(resolvedSourcePath)) {
223
- return fail(`Source path does not exist: ${resolvedSourcePath}`, {
224
- sourcePath: resolvedSourcePath,
225
- })
226
- }
194
+ let addedCount = 0
195
+ let updatedCount = 0
196
+ let skippedCount = 0
227
197
 
228
- const kbRootPath = _getKbRootPath(knowledgeBasePath)
229
- const knowledgeBase = _loadKnowledgeBase(kbRootPath)
230
- const sourceFiles = _collectSourceFiles(resolvedSourcePath)
198
+ for (const filePath of supportedFiles) {
199
+ try {
200
+ const absolutePath = path.resolve(filePath)
201
+ const content = await _readDocumentContent(absolutePath)
202
+ if (!content || !content.trim()) {
203
+ skippedCount += 1
204
+ continue
205
+ }
231
206
 
232
- const supportedFiles = sourceFiles.filter((filePath) => _isSupportedFile(filePath))
233
- let addedCount = 0
234
- let updatedCount = 0
235
- let skippedCount = 0
207
+ const sourceHash = _sha256(content)
208
+ const existingIndex = knowledgeBase.documents.findIndex((item) => item.absolutePath === absolutePath)
236
209
 
237
- for (const filePath of supportedFiles) {
238
- try {
239
- const content = await _readDocumentContent(filePath)
240
- if (!content || !content.trim()) {
210
+ if (existingIndex >= 0) {
211
+ if (knowledgeBase.documents[existingIndex].sourceHash === sourceHash) {
241
212
  skippedCount += 1
242
213
  continue
243
214
  }
244
215
 
245
- const sourceHash = _sha256(content)
246
- const existingIndex = knowledgeBase.documents.findIndex((item) => item.sourcePath === filePath)
247
- if (existingIndex >= 0) {
248
- if (knowledgeBase.documents[existingIndex].sourceHash === sourceHash) {
249
- skippedCount += 1
250
- continue
251
- }
252
- knowledgeBase.documents[existingIndex] = {
253
- ...knowledgeBase.documents[existingIndex],
254
- sourceHash,
255
- size: Buffer.byteLength(content, 'utf8'),
256
- content,
257
- updatedAt: new Date().toISOString(),
258
- }
259
- updatedCount += 1
260
- continue
261
- }
216
+ const summary = await _extractSummary.call(this, content, 320, absolutePath)
262
217
 
263
- knowledgeBase.documents.push({
264
- id: _sha256(filePath).slice(0, 16),
265
- sourcePath: filePath,
218
+ knowledgeBase.documents[existingIndex] = {
219
+ ...knowledgeBase.documents[existingIndex],
266
220
  sourceHash,
267
221
  size: Buffer.byteLength(content, 'utf8'),
268
- content,
269
- createdAt: new Date().toISOString(),
222
+ summary,
270
223
  updatedAt: new Date().toISOString(),
271
- })
272
- addedCount += 1
273
- } catch {
274
- skippedCount += 1
224
+ }
225
+ _saveKnowledgeBase(kbRootPath, knowledgeBase)
226
+ updatedCount += 1
227
+ continue
275
228
  }
229
+
230
+ const summary = await _extractSummary.call(this, content, 320, absolutePath)
231
+
232
+ knowledgeBase.documents.push({
233
+ id: _sha256(absolutePath).slice(0, 16),
234
+ absolutePath,
235
+ sourceHash,
236
+ size: Buffer.byteLength(content, 'utf8'),
237
+ summary,
238
+ createdAt: new Date().toISOString(),
239
+ updatedAt: new Date().toISOString(),
240
+ })
241
+ _saveKnowledgeBase(kbRootPath, knowledgeBase)
242
+ addedCount += 1
243
+ } catch {
244
+ skippedCount += 1
276
245
  }
246
+ }
277
247
 
278
- knowledgeBase.sourceHistory.push({
279
- sourcePath: resolvedSourcePath,
280
- loadedAt: new Date().toISOString(),
281
- scannedFiles: sourceFiles.length,
282
- supportedFiles: supportedFiles.length,
283
- addedCount,
284
- updatedCount,
285
- skippedCount,
286
- })
248
+ knowledgeBase.sourceHistory.push({
249
+ sourcePath: resolvedSourcePath,
250
+ loadedAt: new Date().toISOString(),
251
+ scannedFiles: sourceFiles.length,
252
+ supportedFiles: supportedFiles.length,
253
+ addedCount,
254
+ updatedCount,
255
+ skippedCount,
256
+ mode: reset ? 'create' : 'append',
257
+ })
287
258
 
288
- _saveKnowledgeBase(kbRootPath, knowledgeBase)
289
- return ok({
290
- knowledgeBasePath: kbRootPath,
291
- sourcePath: resolvedSourcePath,
292
- scannedFiles: sourceFiles.length,
293
- supportedFiles: supportedFiles.length,
294
- addedCount,
295
- updatedCount,
296
- skippedCount,
297
- totalDocuments: knowledgeBase.documents.length,
298
- })
259
+ _saveKnowledgeBase(kbRootPath, knowledgeBase)
260
+
261
+ return ok({
262
+ knowledgeBasePath: kbRootPath,
263
+ sourcePath: resolvedSourcePath,
264
+ scannedFiles: sourceFiles.length,
265
+ supportedFiles: supportedFiles.length,
266
+ addedCount,
267
+ updatedCount,
268
+ skippedCount,
269
+ totalDocuments: knowledgeBase.documents.length,
270
+ })
271
+ }
272
+
273
+ async function createKnowledgeBase(sourcePath = '', knowledgeBasePath = '') {
274
+ try {
275
+ return await _upsertKnowledgeBase.call(this, sourcePath, knowledgeBasePath, true)
299
276
  } catch (error) {
300
277
  return fail(error, { sourcePath, knowledgeBasePath })
301
278
  }
302
279
  }
303
280
 
304
- // 读取知识库文档摘要,支持关键词检索
305
- function readKnowledgeBase(keyword = '', knowledgeBasePath = '', limit = 10) {
281
+ async function appendKnowledgeBase(sourcePath = '', knowledgeBasePath = '') {
306
282
  try {
307
- const kbRootPath = _getKbRootPath(knowledgeBasePath)
308
- const knowledgeBase = _loadKnowledgeBase(kbRootPath)
309
- const normalizedKeyword = (keyword || '').trim().toLowerCase()
310
- const maxResult = Number(limit) > 0 ? Number(limit) : 10
311
-
312
- const filtered = knowledgeBase.documents.filter((item) => {
313
- if (!normalizedKeyword) return true
314
- return (
315
- item.sourcePath.toLowerCase().includes(normalizedKeyword) ||
316
- item.content.toLowerCase().includes(normalizedKeyword)
317
- )
318
- })
319
-
320
- const result = filtered.slice(0, maxResult).map((item) => ({
321
- id: item.id,
322
- sourcePath: item.sourcePath,
323
- size: item.size,
324
- updatedAt: item.updatedAt,
325
- preview: (item.content || '').slice(0, 240),
326
- }))
327
-
328
- return ok({
329
- knowledgeBasePath: kbRootPath,
330
- totalDocuments: knowledgeBase.documents.length,
331
- matchedDocuments: filtered.length,
332
- items: result,
333
- })
283
+ return await _upsertKnowledgeBase.call(this, sourcePath, knowledgeBasePath, false)
334
284
  } catch (error) {
335
- return fail(error, { keyword, knowledgeBasePath, limit })
285
+ return fail(error, { sourcePath, knowledgeBasePath })
336
286
  }
337
287
  }
338
288
 
339
- // 按文档ID读取完整内容
340
- function readKnowledgeBaseDocument(documentId, knowledgeBasePath = '') {
341
- try {
342
- if (!documentId) {
343
- return fail('documentId is required')
344
- }
345
- const kbRootPath = _getKbRootPath(knowledgeBasePath)
346
- const knowledgeBase = _loadKnowledgeBase(kbRootPath)
347
- const doc = knowledgeBase.documents.find((item) => item.id === documentId)
348
- if (!doc) {
349
- return fail(`Document not found: ${documentId}`, {
350
- documentId,
351
- knowledgeBasePath: kbRootPath,
352
- })
289
+ function _matchSummary(knowledgeBase, normalizedKeyword = '', maxResult = 10) {
290
+ const filtered = knowledgeBase.documents.filter((item) => {
291
+ if (!normalizedKeyword) return true
292
+ const haystack = `${item.absolutePath || ''} ${item.summary || ''}`.toLowerCase()
293
+ return haystack.includes(normalizedKeyword)
294
+ })
295
+
296
+ return filtered.slice(0, maxResult).map((item) => ({
297
+ id: item.id,
298
+ absolutePath: item.absolutePath,
299
+ size: item.size,
300
+ updatedAt: item.updatedAt,
301
+ summary: item.summary,
302
+ }))
303
+ }
304
+
305
+ async function _queryBySubAgent(keyword, summaryMatches, includeFullDocument = false) {
306
+ if (!this?.Tools?.createSubAgent) {
307
+ return {
308
+ success: false,
309
+ skipped: true,
310
+ reason: 'createSubAgent tool is unavailable in current context',
353
311
  }
354
- return ok({
355
- id: doc.id,
356
- sourcePath: doc.sourcePath,
357
- size: doc.size,
358
- createdAt: doc.createdAt,
359
- updatedAt: doc.updatedAt,
360
- content: doc.content,
361
- })
362
- } catch (error) {
363
- return fail(error, { documentId, knowledgeBasePath })
364
312
  }
313
+
314
+ const prompt = `你是知识库检索子agent,请完成文档检索。
315
+
316
+ 用户关键词:${keyword}
317
+ 是否允许读取全文:${includeFullDocument ? '是' : '否(仅在必要时)'}
318
+ 候选文档(按摘要初筛后)如下:
319
+ ${JSON.stringify(summaryMatches, null, 2)}
320
+
321
+ 执行要求:
322
+ 1. 先使用候选文档的summary进行关键词匹配和排序。
323
+ 2. 当summary不足以回答问题时,再读取对应absolutePath的完整文档内容进行补充。
324
+ 3. 输出结构化结果,必须包含:
325
+ - 命中文档列表(id、absolutePath、匹配原因)
326
+ - 最终结论
327
+ - 若读取全文,列出已读取的absolutePath。
328
+ `
329
+
330
+ return this.Tools.createSubAgent(prompt)
365
331
  }
366
332
 
367
- // 按分块检索知识库内容,适用于后续RAG召回
368
- function searchKnowledgeBaseChunks(keyword = '', knowledgeBasePath = '', chunkSize = 800, overlap = 120, limit = 10) {
333
+ async function queryKnowledgeBase(keyword = '', knowledgeBasePath = '', limit = 10, includeFullDocument = false) {
369
334
  try {
370
- const normalizedKeyword = (keyword || '').trim()
335
+ const normalizedKeyword = String(keyword || '').trim().toLowerCase()
371
336
  if (!normalizedKeyword) {
372
337
  return fail('keyword is required')
373
338
  }
@@ -375,61 +340,26 @@ function searchKnowledgeBaseChunks(keyword = '', knowledgeBasePath = '', chunkSi
375
340
  const kbRootPath = _getKbRootPath(knowledgeBasePath)
376
341
  const knowledgeBase = _loadKnowledgeBase(kbRootPath)
377
342
  const maxResult = Number(limit) > 0 ? Number(limit) : 10
378
- const allChunks = []
379
-
380
- for (const doc of knowledgeBase.documents) {
381
- const chunks = _chunkText(doc.content || '', chunkSize, overlap)
382
- chunks.forEach((chunk, index) => {
383
- const score = _calcKeywordScore(chunk.content, normalizedKeyword)
384
- if (score > 0) {
385
- allChunks.push({
386
- documentId: doc.id,
387
- sourcePath: doc.sourcePath,
388
- chunkIndex: index,
389
- offsetStart: chunk.offsetStart,
390
- offsetEnd: chunk.offsetEnd,
391
- score,
392
- content: chunk.content,
393
- })
394
- }
395
- })
396
- }
397
-
398
- const items = allChunks
399
- .sort((a, b) => b.score - a.score || a.sourcePath.localeCompare(b.sourcePath) || a.chunkIndex - b.chunkIndex)
400
- .slice(0, maxResult)
343
+ const summaryMatches = _matchSummary(knowledgeBase, normalizedKeyword, maxResult)
401
344
 
402
- return ok({
403
- knowledgeBasePath: kbRootPath,
404
- keyword: normalizedKeyword,
405
- totalMatchedChunks: allChunks.length,
406
- items,
407
- })
408
- } catch (error) {
409
- return fail(error, { keyword, knowledgeBasePath, chunkSize, overlap, limit })
410
- }
411
- }
345
+ let subAgentResult = null
346
+ if (summaryMatches.length > 0) {
347
+ subAgentResult = await _queryBySubAgent.call(this, keyword, summaryMatches, includeFullDocument)
348
+ }
412
349
 
413
- // 读取知识库统计信息
414
- function getKnowledgeBaseInfo(knowledgeBasePath = '') {
415
- try {
416
- const kbRootPath = _getKbRootPath(knowledgeBasePath)
417
- const knowledgeBase = _loadKnowledgeBase(kbRootPath)
418
350
  return ok({
419
351
  knowledgeBasePath: kbRootPath,
420
- version: knowledgeBase.version,
421
- name: knowledgeBase.name,
422
- createdAt: knowledgeBase.createdAt,
423
- updatedAt: knowledgeBase.updatedAt,
352
+ keyword,
424
353
  totalDocuments: knowledgeBase.documents.length,
425
- sourceHistory: knowledgeBase.sourceHistory,
354
+ matchedDocuments: summaryMatches.length,
355
+ items: summaryMatches,
356
+ subAgentResult,
426
357
  })
427
358
  } catch (error) {
428
- return fail(error, { knowledgeBasePath })
359
+ return fail(error, { keyword, knowledgeBasePath, limit, includeFullDocument })
429
360
  }
430
361
  }
431
362
 
432
- // 删除知识库目录
433
363
  function deleteKnowledgeBase(knowledgeBasePath = '') {
434
364
  try {
435
365
  const kbRootPath = _getKbRootPath(knowledgeBasePath)
@@ -440,6 +370,7 @@ function deleteKnowledgeBase(knowledgeBasePath = '') {
440
370
  message: 'knowledge base path not found',
441
371
  })
442
372
  }
373
+
443
374
  fs.removeSync(kbRootPath)
444
375
  return ok({
445
376
  knowledgeBasePath: kbRootPath,
@@ -450,209 +381,16 @@ function deleteKnowledgeBase(knowledgeBasePath = '') {
450
381
  }
451
382
  }
452
383
 
453
- // 先删除再重建知识库
454
- async function rebuildKnowledgeBase(sourcePath = '', knowledgeBasePath = '') {
455
- try {
456
- const deleteResult = deleteKnowledgeBase(knowledgeBasePath)
457
- if (!deleteResult.success) {
458
- return deleteResult
459
- }
460
- return await buildKnowledgeBase(sourcePath, knowledgeBasePath)
461
- } catch (error) {
462
- return fail(error, { sourcePath, knowledgeBasePath })
463
- }
464
- }
465
-
466
- // 知识库创建描述
467
- function getKnowledgeBaseCreationDescription() {
468
- return `# Knowledge Base Creation Guide
469
-
470
- ## 目标
471
- 使用本工具在命令执行目录下创建或维护本地知识库(默认目录为 .deepfish-rag),并支持后续持续增量更新。
472
-
473
- ## 能完成的任务
474
- 1. 从用户给定的目录或文件加载文档内容,构建本地知识库。
475
- 2. 自动识别常见文本与文档格式(如 md、txt、json、js、pdf、docx、xlsx 等)。
476
- 3. 在重复导入时执行增量更新:
477
- - 内容未变化:跳过
478
- - 内容已变化:更新
479
- - 新文件:新增
480
- 4. 记录每次构建来源和统计信息(sourceHistory),方便审计和复盘。
481
- 5. 支持删除后重建,快速恢复知识库状态。
482
-
483
- ## 关键函数与协同关系
484
-
485
- ### 1) 构建层
486
- - buildKnowledgeBase(sourcePath, knowledgeBasePath)
487
- - 创建或续加知识库的主入口。
488
- - sourcePath 为空时会交互式要求用户输入文件或目录。
489
- - 默认知识库路径为 process.cwd()/.deepfish-rag。
490
-
491
- 它在内部协同调用:
492
- - _getKbRootPath:统一知识库目录解析。
493
- - _loadKnowledgeBase:读取或初始化 index.json。
494
- - _collectSourceFiles:展开目录得到文件集合。
495
- - _isSupportedFile:过滤可处理文件类型。
496
- - _readDocumentContent:按不同文件类型提取文本。
497
- - _sha256:计算内容哈希,用于增量判断。
498
- - _saveKnowledgeBase:保存最终索引。
499
-
500
- ### 2) 重建层
501
- - deleteKnowledgeBase(knowledgeBasePath)
502
- - 删除现有知识库目录。
503
- - rebuildKnowledgeBase(sourcePath, knowledgeBasePath)
504
- - 先删后建。
505
- - 典型用于“索引异常修复”或“结构升级后重建”。
506
-
507
- ## 推荐执行流程
508
- 1. 调用 buildKnowledgeBase 进行首次构建。
509
- 2. 后续补充文档时再次调用 buildKnowledgeBase(续加)。
510
- 3. 如需彻底刷新:调用 rebuildKnowledgeBase。
511
- 4. 构建完成后再进入检索阶段(read/search 系列函数)。
512
-
513
- ## 面向用户任务的协同策略
514
- - 用户说“请把这个目录做成知识库”:
515
- - buildKnowledgeBase(目录路径)
516
- - 用户说“继续把新资料加进去”:
517
- - buildKnowledgeBase(新目录路径)
518
- - 用户说“从头重建”:
519
- - rebuildKnowledgeBase(目录路径)
520
-
521
- ## 结果校验建议
522
- 构建后建议检查:
523
- 1. getKnowledgeBaseInfo 的 totalDocuments 是否大于 0。
524
- 2. sourceHistory 是否新增一条构建记录。
525
- 3. addedCount / updatedCount / skippedCount 是否符合预期。
526
- `
527
- }
528
-
529
- // 知识库检索描述
530
- function getKnowledgeBaseRetrievalDescription() {
531
- return `# Knowledge Base Retrieval Guide
532
-
533
- ## 目标
534
- 从本地知识库中高效找到“相关文档”与“关键片段”,用于问答、总结、比对和后续 RAG 召回。
535
-
536
- ## 能完成的任务
537
- 1. 查看知识库总体状态与构建历史。
538
- 2. 按关键词筛选文档摘要,快速定位候选文档。
539
- 3. 按文档 ID 读取全文,进行精读分析。
540
- 4. 按分块检索返回命中片段,适合长文档场景。
541
-
542
- ## 关键函数与协同关系
543
-
544
- ### 1) 元信息确认
545
- - getKnowledgeBaseInfo(knowledgeBasePath)
546
- - 获取总文档数、创建时间、更新时间、构建历史。
547
- - 作用:先判断库是否可用,再决定检索策略。
548
-
549
- ### 2) 粗粒度召回(文档级)
550
- - readKnowledgeBase(keyword, knowledgeBasePath, limit)
551
- - 返回文档摘要(id、sourcePath、preview)。
552
- - 作用:先召回候选文档,缩小范围。
553
-
554
- ### 3) 细粒度阅读(全文级)
555
- - readKnowledgeBaseDocument(documentId, knowledgeBasePath)
556
- - 读取指定文档全文。
557
- - 作用:对高价值候选文档做精读与引用。
558
-
559
- ### 4) 片段级召回(chunk级)
560
- - searchKnowledgeBaseChunks(keyword, knowledgeBasePath, chunkSize, overlap, limit)
561
- - 将文档切块并按关键词命中分数排序。
562
- - 作用:在超长文档里快速找到最相关上下文。
563
-
564
- 它在内部协同调用:
565
- - _chunkText:按 chunkSize + overlap 生成可检索片段。
566
- - _calcKeywordScore:计算关键词命中次数并排序。
567
-
568
- ## 推荐检索流程
569
- 1. 调用 getKnowledgeBaseInfo,确认知识库可用。
570
- 2. 调用 readKnowledgeBase(keyword),拿到候选文档列表。
571
- 3. 对重点文档调用 readKnowledgeBaseDocument 进行精读。
572
- 4. 若候选文档过大或命中不精确,调用 searchKnowledgeBaseChunks 做片段召回。
573
- 5. 将片段结果组织为回答证据,必要时回看全文补全上下文。
574
-
575
- ## 典型用户任务协同方案
576
-
577
- ### 场景 A:用户问“知识库里有没有某主题”
578
- 1. readKnowledgeBase(主题词)
579
- 2. 返回候选文档与预览
580
-
581
- ### 场景 B:用户问“请给出该主题的依据段落”
582
- 1. readKnowledgeBase(主题词)
583
- 2. searchKnowledgeBaseChunks(主题词)
584
- 3. 输出高分片段 + 源文件路径
585
-
586
- ### 场景 C:用户问“请基于某篇文档做总结”
587
- 1. readKnowledgeBase(文档名关键词)
588
- 2. readKnowledgeBaseDocument(documentId)
589
- 3. 对全文执行总结
590
-
591
- ## 检索参数建议
592
- 1. limit
593
- - 初筛推荐 5-20
594
- 2. chunkSize
595
- - 一般 600-1200
596
- 3. overlap
597
- - 一般 80-200
598
- - 过小可能断句,过大可能冗余
599
-
600
- ## 结果质量建议
601
- 1. 优先返回包含 sourcePath 与文档 ID 的证据。
602
- 2. 先文档级筛选,再 chunk 级定位,避免全库全文扫描输出过大。
603
- 3. 对高分片段做二次核对,防止关键词误命中。
604
- `
605
- }
606
-
607
384
  const descriptions = [
608
385
  {
609
386
  type: 'function',
610
387
  function: {
611
- name: 'getKnowledgeBaseCreationDescription',
612
- description: '知识库创建与续加的完整说明文档,包含可完成任务、函数协同关系与推荐执行流程。在执行知识库创建、续加或重建前,建议先阅读此文档以明确使用方法与注意事项。',
613
- parameters: {
614
- type: 'object',
615
- properties: {},
616
- },
617
- },
618
- },
619
- {
620
- type: 'function',
621
- function: {
622
- name: 'getKnowledgeBaseRetrievalDescription',
623
- description: '知识库检索的完整说明文档,包含检索策略、函数协同关系与典型任务执行方案。在执行知识库检索前,建议先阅读此文档以明确使用方法与注意事项。',
624
- parameters: {
625
- type: 'object',
626
- properties: {},
627
- },
628
- },
629
- },
630
- {
631
- type: 'function',
632
- function: {
633
- name: 'buildKnowledgeBase',
634
- description: '创建或续加知识库。默认知识库路径为命令执行目录下的 .deepfish-rag。sourcePath 为空时会提示用户输入源文件目录或文件路径。',
388
+ name: 'createKnowledgeBase',
389
+ description: '创建知识库(先删除旧库再重建),存储文档绝对路径和约300字摘要。',
635
390
  parameters: {
636
391
  type: 'object',
637
392
  properties: {
638
393
  sourcePath: { type: 'string', description: '源文件目录或文件路径。为空时会交互输入。' },
639
- knowledgeBasePath: { type: 'string', description: '知识库目录路径,默认 .deepfish-rag(相对命令执行目录)。' },
640
- },
641
- required: [],
642
- },
643
- },
644
- },
645
- {
646
- type: 'function',
647
- function: {
648
- name: 'readKnowledgeBase',
649
- description: '读取知识库中的文档摘要,支持关键词过滤。可用于快速检索知识库内容。',
650
- parameters: {
651
- type: 'object',
652
- properties: {
653
- keyword: { type: 'string', description: '关键词,不传表示返回全部文档摘要。' },
654
- knowledgeBasePath: { type: 'string', description: '知识库目录路径,默认 .deepfish-rag。' },
655
- limit: { type: 'number', description: '返回条数上限,默认 10。' },
656
394
  },
657
395
  required: [],
658
396
  },
@@ -661,27 +399,12 @@ const descriptions = [
661
399
  {
662
400
  type: 'function',
663
401
  function: {
664
- name: 'readKnowledgeBaseDocument',
665
- description: '按文档ID读取知识库中的完整文档内容。',
402
+ name: 'appendKnowledgeBase',
403
+ description: '续加知识库(增量导入),存储文档绝对路径和约300字摘要。',
666
404
  parameters: {
667
405
  type: 'object',
668
406
  properties: {
669
- documentId: { type: 'string', description: '文档ID(由 buildKnowledgeBase 生成)。' },
670
- knowledgeBasePath: { type: 'string', description: '知识库目录路径,默认 .deepfish-rag。' },
671
- },
672
- required: ['documentId'],
673
- },
674
- },
675
- },
676
- {
677
- type: 'function',
678
- function: {
679
- name: 'getKnowledgeBaseInfo',
680
- description: '读取知识库元信息与历史加载记录(sourceHistory)。',
681
- parameters: {
682
- type: 'object',
683
- properties: {
684
- knowledgeBasePath: { type: 'string', description: '知识库目录路径,默认 .deepfish-rag。' },
407
+ sourcePath: { type: 'string', description: '源文件目录或文件路径。为空时会交互输入。' },
685
408
  },
686
409
  required: [],
687
410
  },
@@ -690,16 +413,14 @@ const descriptions = [
690
413
  {
691
414
  type: 'function',
692
415
  function: {
693
- name: 'searchKnowledgeBaseChunks',
694
- description: '对知识库进行分块检索,返回命中关键词的文本块(chunk),用于RAG召回。',
416
+ name: 'queryKnowledgeBase',
417
+ description: '查询知识库:先按摘要匹配关键词,再由子agent在必要时读取命中文档的完整内容。',
695
418
  parameters: {
696
419
  type: 'object',
697
420
  properties: {
698
421
  keyword: { type: 'string', description: '检索关键词。' },
699
- knowledgeBasePath: { type: 'string', description: '知识库目录路径,默认 .deepfish-rag。' },
700
- chunkSize: { type: 'number', description: '分块长度,默认 800。' },
701
- overlap: { type: 'number', description: '分块重叠长度,默认 120。' },
702
422
  limit: { type: 'number', description: '返回数量上限,默认 10。' },
423
+ includeFullDocument: { type: 'boolean', description: '是否允许子agent读取全文,默认 false。' },
703
424
  },
704
425
  required: ['keyword'],
705
426
  },
@@ -712,24 +433,7 @@ const descriptions = [
712
433
  description: '删除知识库目录(默认删除命令执行目录下的 .deepfish-rag)。',
713
434
  parameters: {
714
435
  type: 'object',
715
- properties: {
716
- knowledgeBasePath: { type: 'string', description: '知识库目录路径,默认 .deepfish-rag。' },
717
- },
718
- required: [],
719
- },
720
- },
721
- },
722
- {
723
- type: 'function',
724
- function: {
725
- name: 'rebuildKnowledgeBase',
726
- description: '重建知识库:先删除原知识库,再从源目录/文件重新构建。',
727
- parameters: {
728
- type: 'object',
729
- properties: {
730
- sourcePath: { type: 'string', description: '源文件目录或文件路径。为空时会交互输入。' },
731
- knowledgeBasePath: { type: 'string', description: '知识库目录路径,默认 .deepfish-rag。' },
732
- },
436
+ properties: {},
733
437
  required: [],
734
438
  },
735
439
  },
@@ -737,20 +441,15 @@ const descriptions = [
737
441
  ]
738
442
 
739
443
  const functions = {
740
- getKnowledgeBaseCreationDescription,
741
- getKnowledgeBaseRetrievalDescription,
742
- buildKnowledgeBase,
743
- readKnowledgeBase,
744
- readKnowledgeBaseDocument,
745
- getKnowledgeBaseInfo,
746
- searchKnowledgeBaseChunks,
444
+ createKnowledgeBase,
445
+ appendKnowledgeBase,
446
+ queryKnowledgeBase,
747
447
  deleteKnowledgeBase,
748
- rebuildKnowledgeBase,
749
448
  }
750
449
 
751
450
  const EmbeddingTool = {
752
451
  name: 'EmbeddingTool',
753
- description: '提供本地知识库构建/读取能力,默认知识库路径为命令执行目录下的 .deepfish-rag',
452
+ description: '提供本地知识库创建、续加、查询、删除能力(索引仅存摘要和绝对路径)',
754
453
  platform: 'all',
755
454
  descriptions,
756
455
  functions,
@@ -758,6 +457,3 @@ const EmbeddingTool = {
758
457
  }
759
458
 
760
459
  module.exports = EmbeddingTool
761
-
762
-
763
-
@@ -420,7 +420,33 @@ async function imagesToPdf(imagePaths, outputPath, options = {}) {
420
420
 
421
421
  // ─── 工具描述 ─────────────────────────────────────────────────────────────────
422
422
 
423
+
424
+ // ─── 使用说明 ─────────────────────────────────────────────────────────────────
425
+
426
+ function imgReadme() {
427
+ return `【IMG 工具使用说明】
428
+ 1. 优先使用本工具内置函数完成任务(元数据读取、缩放、裁剪、旋转、格式转换、压缩、水印等)。
429
+ 2. 如果内置函数无法满足需求(如复杂滤镜处理、特殊格式转换、高级图像合成),再尝试使用 ImageMagick 命令行。
430
+ 3. 在调用 ImageMagick 前,先检测系统是否已安装 ImageMagick:
431
+ - 已安装:直接使用 ImageMagick 命令行继续处理。
432
+ - 未安装:询问用户是否允许安装。
433
+ 4. 若用户同意安装:引导完成安装后继续执行原任务。
434
+ 5. 若用户拒绝安装:明确告知当前能力限制,并终止该操作。
435
+
436
+ 建议:
437
+ - 常规图像处理优先使用内置函数,速度更快且依赖更少。
438
+ - 仅在确实需要高级图像处理能力时才启用 ImageMagick 路径。`
439
+ }
440
+
423
441
  const descriptions = [
442
+ {
443
+ type: 'function',
444
+ function: {
445
+ name: 'imgReadme',
446
+ description: '获取 IMG 工具集的使用说明, 调用函数前必须先查看本说明。',
447
+ parameters: {},
448
+ }
449
+ },
424
450
  {
425
451
  type: 'function',
426
452
  function: {
@@ -707,6 +733,7 @@ const descriptions = [
707
733
  // ─── 导出 ──────────────────────────────────────────────────────────────────────
708
734
 
709
735
  const functions = {
736
+ imgReadme,
710
737
  getImageInfo,
711
738
  resizeImage,
712
739
  cropImage,
@@ -372,7 +372,33 @@ async function getPptxTextStats(filePath) {
372
372
 
373
373
  // ─── 工具描述 ─────────────────────────────────────────────────────────────────
374
374
 
375
+
376
+ // ─── 使用说明 ─────────────────────────────────────────────────────────────────
377
+
378
+ function pptxReadme() {
379
+ return `【PPTX 工具使用说明】
380
+ 1. 优先使用本工具内置函数完成任务(信息读取、文本提取、搜索、创建演示文稿、追加幻灯片、文本替换、合并、图片提取等)。
381
+ 2. 如果内置函数无法满足需求(如复杂动画保真、特殊版式处理、跨格式高级转换),再尝试使用 LibreOffice 命令行。
382
+ 3. 在调用 LibreOffice 前,先检测系统是否已安装 LibreOffice:
383
+ - 已安装:直接使用 LibreOffice 命令行继续处理。
384
+ - 未安装:询问用户是否允许安装。
385
+ 4. 若用户同意安装:引导完成安装后继续执行原任务。
386
+ 5. 若用户拒绝安装:明确告知当前能力限制,并终止该操作。
387
+
388
+ 建议:
389
+ - 常规演示文稿处理优先使用内置函数,速度更快且依赖更少。
390
+ - 仅在确实需要高保真格式转换或复杂版式时才启用 LibreOffice 路径。`
391
+ }
392
+
375
393
  const descriptions = [
394
+ {
395
+ type: 'function',
396
+ function: {
397
+ name: 'pptxReadme',
398
+ description: '获取 PPTX 工具集的使用说明, 调用函数前必须先查看本说明。',
399
+ parameters: {},
400
+ }
401
+ },
376
402
  {
377
403
  type: 'function',
378
404
  function: {
@@ -517,6 +543,7 @@ options 可选:{ title, subject, author, company, layout }。
517
543
  // ─── 导出 ──────────────────────────────────────────────────────────────────────
518
544
 
519
545
  const functions = {
546
+ pptxReadme,
520
547
  getPptxInfo,
521
548
  readPptxText,
522
549
  searchPptxText,
@@ -0,0 +1,36 @@
1
+ function videoReadme() {
2
+ return `【VIDEO 工具使用说明】
3
+ 1. 优先尝试使用 FFmpeg 命令行。
4
+ 3. 在调用 FFmpeg 前,先检测系统是否已安装 FFmpeg:
5
+ - 已安装:直接使用 FFmpeg 命令行继续处理。
6
+ - 未安装:询问用户是否允许安装。
7
+ 4. 若用户同意安装:引导完成安装后继续执行原任务。
8
+ 5. 若用户拒绝安装:明确告知当前能力限制,并终止该操作。`
9
+ }
10
+
11
+ const descriptions = [
12
+ {
13
+ type: 'function',
14
+ function: {
15
+ name: 'videoReadme',
16
+ description: '获取 VIDEO 工具集的使用说明, 在处理音频、视频文件前必须先查看本说明。',
17
+ parameters: {},
18
+ },
19
+ },
20
+ ]
21
+
22
+ const functions = {
23
+ videoReadme,
24
+ }
25
+
26
+ const VideoTool = {
27
+ name: 'VideoTool',
28
+ description: '提供音频、视频处理能力说明',
29
+ platform: 'all',
30
+ descriptions,
31
+ functions,
32
+ isSystem: true
33
+ }
34
+
35
+ module.exports = VideoTool
36
+
@@ -22,6 +22,21 @@ function resolvePath(filePath) {
22
22
 
23
23
  // ─── 工具函数 ─────────────────────────────────────────────────────────────────
24
24
 
25
+ function xlsxReadme() {
26
+ return `【XLSX 工具使用说明】
27
+ 1. 优先使用本工具内置函数完成任务(读取、写入、搜索、合并、CSV 互转等)。
28
+ 2. 如果内置函数无法满足需求(如复杂格式保真、特殊公式处理、跨格式高级转换),再尝试使用 LibreOffice 命令行。
29
+ 3. 在调用 LibreOffice 前,先检测系统是否已安装 LibreOffice:
30
+ - 已安装:直接使用 LibreOffice 命令行继续处理。
31
+ - 未安装:询问用户是否允许安装。
32
+ 4. 若用户同意安装:引导完成安装后继续执行原任务。
33
+ 5. 若用户拒绝安装:明确告知当前能力限制,并终止该操作。
34
+
35
+ 建议:
36
+ - 简单与结构化数据处理优先使用内置函数,速度更快且依赖更少。
37
+ - 仅在确实需要高保真格式转换时才启用 LibreOffice 路径。`
38
+ }
39
+
25
40
  /**
26
41
  * 获取 XLSX 文件基本信息(工作表名称、行列数等)
27
42
  */
@@ -337,6 +352,14 @@ async function getSheetStats(filePath, sheetName) {
337
352
  // ─── 工具描述 ─────────────────────────────────────────────────────────────────
338
353
 
339
354
  const descriptions = [
355
+ {
356
+ type: 'function',
357
+ function: {
358
+ name: 'xlsxReadme',
359
+ description: '获取 XLSX 工具集的使用说明, 调用函数前必须先查看本说明。',
360
+ parameters: {},
361
+ }
362
+ },
340
363
  {
341
364
  type: 'function',
342
365
  function: {
@@ -559,6 +582,7 @@ const descriptions = [
559
582
  // ─── 导出 ──────────────────────────────────────────────────────────────────────
560
583
 
561
584
  const functions = {
585
+ xlsxReadme,
562
586
  getXlsxInfo,
563
587
  getSheetNames,
564
588
  readSheet,
@@ -1,5 +1,3 @@
1
- const path = require('path')
2
-
3
1
  const descriptions = [
4
2
  {
5
3
  type: 'function',
@@ -176,8 +174,8 @@ const functions = {
176
174
  },
177
175
  systemFileManagement_copyFile: function(srcPath, destPath) {
178
176
  try {
179
- const fullSourcePath = path.resolve(process.cwd(), sourcePath)
180
- const fullDestPath = path.resolve(process.cwd(), destinationPath)
177
+ const fullSourcePath = path.resolve(process.cwd(), srcPath)
178
+ const fullDestPath = path.resolve(process.cwd(), destPath)
181
179
  const destDirPath = path.dirname(fullDestPath)
182
180
 
183
181
  fs.ensureDirSync(destDirPath)
@@ -2,8 +2,6 @@ const defaultConfig = {
2
2
  ai: [],
3
3
  currentAi: '',
4
4
  maxIterations: -1, // ai完成工作流的最大迭代次数,-1表示无限制
5
- maxMessagesLength: 150000, // 最大压缩长度,-1表示无限制
6
- maxMessagesCount: 100, // 最大压缩数量,-1表示无限制
7
5
  maxMemoryExpireTime: 30, // 整个会话的最大过期时间,单位天,-1表示无限制, 0表示不记录
8
6
  maxLogExpireTime: 3, // 日志过期时间,单位天,-1表示无限制,0表示不记录
9
7
  maxBlockFileSize: 20, // 最大分块文件大小,单位KB;超过该大小的文件需要分块处理