foliko 1.0.67 → 1.0.69

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.
@@ -58,6 +58,9 @@ class AgentChatHandler extends EventEmitter {
58
58
  this._encoder = null
59
59
  this._compressionCount = 0 // 压缩次数统计
60
60
 
61
+ // 工具结果压缩配置
62
+ this._maxToolResultSize = config.maxToolResultSize || 3000 // 工具结果超过此大小则压缩
63
+
61
64
  // 初始化编码器
62
65
  this._initEncoder()
63
66
  }
@@ -201,15 +204,85 @@ ${conversationText}
201
204
  3. 不要超过 1000 字
202
205
  4. 用中文回复`
203
206
 
204
- // 直接使用已配置的 AI 客户端生成摘要(复用主 Agent 的配置)
205
- const result = await this._aiClient.generate({
206
- messages: [
207
- { role: 'user', content: summarizePrompt }
208
- ],
207
+ // 使用 AI SDK 6.x 的 generateText
208
+ const { generateText } = require('ai')
209
+ const { text } = await generateText({
210
+ model: this._aiClient,
211
+ prompt: summarizePrompt,
209
212
  ...this.providerOptions
210
213
  })
211
214
 
212
- return result.text || '(总结生成失败)'
215
+ return text || '(总结生成失败)'
216
+ }
217
+
218
+ /**
219
+ * 检查工具结果是否需要压缩
220
+ * @param {any} result - 工具返回结果
221
+ * @returns {boolean}
222
+ * @private
223
+ */
224
+ _shouldCompressToolResult(result) {
225
+ if (!result || this._maxToolResultSize <= 0) return false
226
+
227
+ // 计算结果的大小
228
+ let size = 0
229
+ if (typeof result === 'string') {
230
+ size = result.length
231
+ } else if (typeof result === 'object') {
232
+ try {
233
+ size = JSON.stringify(result).length
234
+ } catch {
235
+ size = String(result).length
236
+ }
237
+ }
238
+
239
+ return size > this._maxToolResultSize
240
+ }
241
+
242
+ /**
243
+ * 压缩工具结果
244
+ * @param {any} result - 工具返回结果
245
+ * @returns {Promise<any>} 压缩后的结果
246
+ * @private
247
+ */
248
+ async _compressToolResult(result) {
249
+ if (!this._shouldCompressToolResult(result)) {
250
+ return result
251
+ }
252
+
253
+ if (!this._aiClient) {
254
+ console.warn('[AgentChat] Cannot compress tool result: no AI client')
255
+ return result
256
+ }
257
+
258
+ try {
259
+ const originalSize = typeof result === 'string' ? result.length : JSON.stringify(result).length
260
+ const resultStr = typeof result === 'string' ? result : JSON.stringify(result, null, 2)
261
+
262
+ // 构建压缩提示
263
+ const compressPrompt = `以下是一个工具执行结果,长度 ${originalSize} 字符。请简洁地总结其核心内容,保留关键数据和信息:
264
+
265
+ ${resultStr.substring(0, 8000)}${resultStr.length > 8000 ? '\n...(内容已截断)' : ''}
266
+
267
+ 请用简洁的语言总结(不超过 500 字):`
268
+
269
+ // 使用 AI SDK 6.x 的 generateText
270
+ const { generateText } = require('ai')
271
+ const { text } = await generateText({
272
+ model: this._aiClient,
273
+ prompt: compressPrompt,
274
+ ...this.providerOptions
275
+ })
276
+
277
+ const summary = text || '(压缩失败,使用原始结果)'
278
+ const compressed = `[工具结果已压缩: 原始大小 ${originalSize} 字符 → ${summary.length} 字符]\n\n${summary}`
279
+
280
+ console.log(`[AgentChat] Tool result compressed: ${originalSize} → ${summary.length} chars`)
281
+ return compressed
282
+ } catch (err) {
283
+ console.warn('[AgentChat] Tool result compression failed:', err.message)
284
+ return result
285
+ }
213
286
  }
214
287
 
215
288
  /**
@@ -280,6 +353,7 @@ ${conversationText}
280
353
  async chat(message, options = {}) {
281
354
  const context = { sessionId: options.sessionId || null, isStream: false }
282
355
  const framework = this.agent.framework
356
+ const self = this // 保存引用用于回调
283
357
 
284
358
  // 动态导入 AI SDK
285
359
  const { tool, ToolLoopAgent } = await this._importAI()
@@ -319,7 +393,11 @@ ${conversationText}
319
393
  return agent.generate({ messages, ...this.providerOptions })
320
394
  })
321
395
 
322
- if (result.text) {
396
+ // 处理返回的消息历史:只保留 user 和 assistant 消息,让 SDK 自动处理 tool 消息
397
+ if (result.messages && Array.isArray(result.messages)) {
398
+ // 只保留 user 和 assistant 消息,SDK 会自动维护 tool 消息
399
+ this._messages = result.messages.filter(m => m.role === 'user' || m.role === 'assistant')
400
+ } else if (result.text) {
323
401
  this._messages.push({
324
402
  role: 'assistant',
325
403
  content: result.text
@@ -366,6 +444,7 @@ ${conversationText}
366
444
 
367
445
  const maxSteps = options.maxSteps || this._maxSteps
368
446
  const tools = this._getAITools(tool)
447
+ const self = this // 保存引用用于回调
369
448
 
370
449
  if (!this._aiClient) {
371
450
  throw new Error('AI client not configured.')
@@ -391,7 +470,11 @@ ${conversationText}
391
470
  const stream = result.fullStream
392
471
  let fullText = ''
393
472
 
394
- for await (const part of stream) {
473
+ // 流式迭代器
474
+ const iterator = stream[Symbol.asyncIterator] ? stream : stream.fullStream
475
+ const finalMessages = []
476
+
477
+ for await (const part of (iterator || stream)) {
395
478
  if (part.type === 'text-delta') {
396
479
  const text = part.text || part.textDelta || ''
397
480
  fullText += text
@@ -401,18 +484,27 @@ ${conversationText}
401
484
  } else if (part.type === 'tool-call') {
402
485
  yield { type: 'tool-call', toolName: part.toolName, args: part.input }
403
486
  } else if (part.type === 'tool-result') {
487
+ // 保存到临时消息列表
488
+ finalMessages.push({ role: 'tool', content: part.output, toolName: part.toolName })
404
489
  yield { type: 'tool-result', toolName: part.toolName, result: part.output }
405
490
  } else if (part.type === 'error') {
406
491
  yield { type: 'error', error: part.error }
407
492
  }
408
493
  }
409
494
 
410
- if (fullText) {
411
- this._messages.push({
412
- role: 'assistant',
413
- content: fullText
414
- })
415
- }
495
+ // 暂时禁用压缩以调试 schema 问题
496
+ // for (const msg of finalMessages) {
497
+ // if (msg.content) {
498
+ // const contentSize = typeof msg.content === 'string' ? msg.content.length : JSON.stringify(msg.content).length
499
+ // if (contentSize > self._maxToolResultSize) {
500
+ // msg.content = await self._compressToolResult(msg.content)
501
+ // }
502
+ // }
503
+ // }
504
+
505
+ // 只保留 user 和 assistant 消息,让 SDK 自动处理 tool 消息
506
+ const assistantMsg = { role: 'assistant', content: fullText }
507
+ this._messages.push(assistantMsg)
416
508
  } catch (err) {
417
509
  this.emit('error', { error: err.message })
418
510
  yield { type: 'error', error: err.message }
@@ -215,7 +215,7 @@ class Framework extends EventEmitter {
215
215
  name: `session_${sessionId}`,
216
216
  ...config
217
217
  }
218
-
218
+
219
219
  // 如果没有提供 AI 相关参数,从 AI 插件获取
220
220
  if (!agentConfig.apiKey) {
221
221
  const aiPlugin = this.pluginManager.get('ai')
@@ -239,6 +239,86 @@ class Framework extends EventEmitter {
239
239
  return agent
240
240
  }
241
241
 
242
+ /**
243
+ * 创建子Agent(具有独立工具集的轻量级Agent)
244
+ * @param {Object} config - 子Agent配置
245
+ * @param {string} config.name - 子Agent名称
246
+ * @param {string} config.role - 角色描述(用于智能选择)
247
+ * @param {string} [config.description] - 供主Agent理解的描述
248
+ * @param {Object} [config.tools] - 自定义工具 { name: toolDef }
249
+ * @param {string[]} [config.parentTools] - 从父Agent继承的工具名称列表
250
+ * @param {Object} [config.llmConfig] - 独立LLM配置
251
+ * @returns {Agent} 创建的子Agent
252
+ */
253
+ createSubAgent(config) {
254
+ const {
255
+ name,
256
+ role,
257
+ description = '',
258
+ tools = {},
259
+ parentTools, // 如果不传,默认继承主agent所有工具
260
+ llmConfig = null
261
+ } = config
262
+
263
+ // 构建子Agent配置
264
+ const agentConfig = {
265
+ name: `subagent_${name}`,
266
+ role: role,
267
+ systemPrompt: role, // 使用 role 作为 systemPrompt
268
+ ...(llmConfig || {}) // 如果提供了独立LLM配置,合并
269
+ }
270
+
271
+ // 如果没有提供 AI 相关参数,从 AI 插件获取
272
+ if (!agentConfig.apiKey) {
273
+ const aiPlugin = this.pluginManager.get('ai')
274
+ if (aiPlugin) {
275
+ agentConfig.apiKey = aiPlugin.config.apiKey
276
+ agentConfig.provider = agentConfig.provider || aiPlugin.config.provider
277
+ agentConfig.model = agentConfig.model || aiPlugin.config.model
278
+ agentConfig.baseURL = agentConfig.baseURL || aiPlugin.config.baseURL
279
+ agentConfig.providerOptions = agentConfig.providerOptions || aiPlugin.config.providerOptions || {}
280
+ }
281
+ }
282
+
283
+ // 创建 Agent
284
+ const agent = new Agent(this, agentConfig)
285
+
286
+ // 注册自定义工具
287
+ for (const [toolName, toolDef] of Object.entries(tools)) {
288
+ if (toolDef && typeof toolDef === 'object') {
289
+ agent.registerTool({
290
+ name: toolName,
291
+ description: toolDef.description || '',
292
+ inputSchema: toolDef.inputSchema,
293
+ execute: toolDef.execute
294
+ })
295
+ }
296
+ }
297
+
298
+ // 从父Agent继承工具
299
+ if (this._mainAgent) {
300
+ const parentToolsDefs = this._mainAgent.getTools()
301
+ if (parentTools === undefined) {
302
+ // 如果没有指定 parentTools,默认继承所有工具
303
+ for (const toolDef of parentToolsDefs) {
304
+ agent.registerTool(toolDef)
305
+ }
306
+ } else if (Array.isArray(parentTools) && parentTools.length > 0) {
307
+ // 指定了要继承的工具列表
308
+ for (const toolName of parentTools) {
309
+ const toolDef = parentToolsDefs.find(t => t.name === toolName)
310
+ if (toolDef) {
311
+ agent.registerTool(toolDef)
312
+ }
313
+ }
314
+ }
315
+ }
316
+
317
+ this._agents.push(agent)
318
+ this.emit('agent:created', agent)
319
+ return agent
320
+ }
321
+
242
322
  /**
243
323
  * 获取 AI 插件
244
324
  * @returns {Object|undefined}
@@ -1,58 +1,58 @@
1
- /**
2
- * Executor 基类
3
- * 执行器的基类,定义执行器接口
4
- */
5
-
6
- const { EventEmitter } = require('../utils/event-emitter')
7
-
8
- class ExecutorBase extends EventEmitter {
9
- /**
10
- * @param {string} name - 执行器名称
11
- */
12
- constructor(name) {
13
- super()
14
- this.name = name
15
- this._enabled = true
16
- }
17
-
18
- /**
19
- * 执行
20
- * @param {Object} params - 执行参数
21
- * @returns {Promise<any>}
22
- */
23
- async execute(params) {
24
- throw new Error('execute() must be implemented')
25
- }
26
-
27
- /**
28
- * 启用执行器
29
- */
30
- enable() {
31
- this._enabled = true
32
- return this
33
- }
34
-
35
- /**
36
- * 禁用执行器
37
- */
38
- disable() {
39
- this._enabled = false
40
- return this
41
- }
42
-
43
- /**
44
- * 是否启用
45
- */
46
- isEnabled() {
47
- return this._enabled
48
- }
49
-
50
- /**
51
- * 销毁
52
- */
53
- destroy() {
54
- this.removeAllListeners()
55
- }
56
- }
57
-
58
- module.exports = { ExecutorBase }
1
+ /**
2
+ * Executor 基类
3
+ * 执行器的基类,定义执行器接口
4
+ */
5
+
6
+ const { EventEmitter } = require('../utils/event-emitter')
7
+
8
+ class ExecutorBase extends EventEmitter {
9
+ /**
10
+ * @param {string} name - 执行器名称
11
+ */
12
+ constructor(name) {
13
+ super()
14
+ this.name = name
15
+ this._enabled = true
16
+ }
17
+
18
+ /**
19
+ * 执行
20
+ * @param {Object} params - 执行参数
21
+ * @returns {Promise<any>}
22
+ */
23
+ async execute(params) {
24
+ throw new Error('execute() must be implemented')
25
+ }
26
+
27
+ /**
28
+ * 启用执行器
29
+ */
30
+ enable() {
31
+ this._enabled = true
32
+ return this
33
+ }
34
+
35
+ /**
36
+ * 禁用执行器
37
+ */
38
+ disable() {
39
+ this._enabled = false
40
+ return this
41
+ }
42
+
43
+ /**
44
+ * 是否启用
45
+ */
46
+ isEnabled() {
47
+ return this._enabled
48
+ }
49
+
50
+ /**
51
+ * 销毁
52
+ */
53
+ destroy() {
54
+ this.removeAllListeners()
55
+ }
56
+ }
57
+
58
+ module.exports = { ExecutorBase }
package/test-server.js DELETED
@@ -1,25 +0,0 @@
1
- const { serve } = require('@hono/node-server');
2
- const { Hono } = require('hono');
3
-
4
- const app = new Hono();
5
-
6
- // 简单路由
7
- app.get('/test', (c) => {
8
- console.log('Handler called');
9
- return c.json({ message: 'Hello World' });
10
- });
11
-
12
- const server = serve({
13
- fetch: app.fetch,
14
- port: 3001
15
- });
16
-
17
- server.on('request', (req) => {
18
- console.log('Request:', req.method, req.url);
19
- });
20
-
21
- server.on('error', (err) => {
22
- console.error('Server error:', err);
23
- });
24
-
25
- console.log('Server started on port 3001');
package/test.txt DELETED
@@ -1,3 +0,0 @@
1
- Hello from static resource test!
2
- This is a test file for verifying static resource serving.
3
- Timestamp: 2026-03-24