foliko 1.0.40 → 1.0.41

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.
@@ -96,6 +96,9 @@ class AgentChatHandler extends EventEmitter {
96
96
  * @param {Object} options - 选项
97
97
  */
98
98
  async chat(message, options = {}) {
99
+ const context = { sessionId: options.sessionId || null, isStream: false }
100
+ const framework = this.agent.framework
101
+
99
102
  // 动态导入 AI SDK
100
103
  const { tool, ToolLoopAgent } = await this._importAI()
101
104
 
@@ -108,32 +111,27 @@ class AgentChatHandler extends EventEmitter {
108
111
  const maxSteps = options.maxSteps || this._maxSteps
109
112
  const tools = this._getAITools(tool)
110
113
 
111
- // 如果没有 AI 客户端,抛出错误
112
114
  if (!this._aiClient) {
113
- throw new Error('AI client not configured. Please set up AI plugin.')
115
+ throw new Error('AI client not configured.')
114
116
  }
115
117
 
116
- try {
117
- // 使用 ToolLoopAgent 处理工具调用循环
118
- const agent = new ToolLoopAgent({
119
- model: this._aiClient,
120
- instructions: this._systemPrompt,
121
- tools: tools,
122
- stopWhen: (step) => step.stepCount >= maxSteps
123
- })
118
+ const agent = new ToolLoopAgent({
119
+ model: this._aiClient,
120
+ instructions: this._systemPrompt,
121
+ tools: tools,
122
+ stopWhen: (step) => step.stepCount >= maxSteps
123
+ })
124
124
 
125
- // 构建消息列表
126
- const messages = [
127
- ...this._cleanMessages(this._messages)
128
- ]
125
+ const messages = [
126
+ ...this._cleanMessages(this._messages)
127
+ ]
129
128
 
130
- // 生成响应
131
- const result = await agent.generate({
132
- messages: messages,
133
- providerOptions: this.providerOptions
129
+ try {
130
+ // 使用 runWithContext 让工具执行时能获取 sessionId
131
+ const result = await framework.runWithContext(context, async () => {
132
+ return agent.generate({ messages, ...this.providerOptions })
134
133
  })
135
134
 
136
- // 添加助手消息到历史
137
135
  if (result.text) {
138
136
  this._messages.push({
139
137
  role: 'assistant',
@@ -159,6 +157,9 @@ class AgentChatHandler extends EventEmitter {
159
157
  * @param {Object} options - 选项
160
158
  */
161
159
  async *chatStream(message, options = {}) {
160
+ const context = { sessionId: options.sessionId || null, isStream: true }
161
+ const framework = this.agent.framework
162
+
162
163
  // 动态导入 AI SDK
163
164
  const { tool, ToolLoopAgent } = await this._importAI()
164
165
 
@@ -171,12 +172,10 @@ class AgentChatHandler extends EventEmitter {
171
172
  const maxSteps = options.maxSteps || this._maxSteps
172
173
  const tools = this._getAITools(tool)
173
174
 
174
- // 如果没有 AI 客户端,抛出错误
175
175
  if (!this._aiClient) {
176
- throw new Error('AI client not configured. Please set up AI plugin.')
176
+ throw new Error('AI client not configured.')
177
177
  }
178
178
 
179
- // 使用 ToolLoopAgent 流式接口
180
179
  const agent = new ToolLoopAgent({
181
180
  model: this._aiClient,
182
181
  instructions: this._systemPrompt,
@@ -189,9 +188,9 @@ class AgentChatHandler extends EventEmitter {
189
188
  ]
190
189
 
191
190
  try {
192
- const result = await agent.stream({
193
- messages: messages,
194
- providerOptions: this.providerOptions
191
+ // 使用 runWithContext 让工具执行时能获取 sessionId(支持并行)
192
+ const result = await framework.runWithContext(context, async () => {
193
+ return agent.stream({ messages, ...this.providerOptions })
195
194
  })
196
195
 
197
196
  const stream = result.fullStream
@@ -203,7 +202,6 @@ class AgentChatHandler extends EventEmitter {
203
202
  fullText += text
204
203
  yield { type: 'text', text }
205
204
  } else if (part.type === 'reasoning') {
206
- // 通过事件发射推理内容
207
205
  this.emit('thinking', { content: part.text })
208
206
  } else if (part.type === 'tool-call') {
209
207
  yield { type: 'tool-call', toolName: part.toolName, args: part.input }
@@ -214,7 +212,6 @@ class AgentChatHandler extends EventEmitter {
214
212
  }
215
213
  }
216
214
 
217
- // 保存消息到历史
218
215
  if (fullText) {
219
216
  this._messages.push({
220
217
  role: 'assistant',
package/src/core/agent.js CHANGED
@@ -47,6 +47,10 @@ class Agent extends EventEmitter {
47
47
  // 子Agent管理
48
48
  this._subAgents = new Map()
49
49
 
50
+ // 消息队列(用于 pushMessage)
51
+ this._messageQueue = []
52
+ this._isProcessingQueue = false
53
+
50
54
  // 处理后的 system prompt (带上下文)
51
55
  this.systemPrompt = this._buildSystemPrompt()
52
56
 
@@ -447,14 +451,80 @@ class Agent extends EventEmitter {
447
451
  const result = await this._chatHandler.chat(enhancedMessage, options)
448
452
  this._status = 'idle'
449
453
  this.emit('status', { status: 'idle' })
454
+
455
+ // 处理队列中的下一条消息
456
+ setImmediate(() => this._processQueue())
457
+
450
458
  return result
451
459
  } catch (err) {
452
460
  this._status = 'error'
453
461
  this.emit('status', { status: 'error', error: err.message })
462
+
463
+ // 发生错误时也要处理队列
464
+ setImmediate(() => this._processQueue())
465
+
454
466
  throw err
455
467
  }
456
468
  }
457
469
 
470
+ /**
471
+ * 推送消息(自动继承当前 sessionId 上下文,自动排队)
472
+ * 工具中调用此方法,自动带上当前执行上下文的 sessionId
473
+ * 如果 agent 忙碌,消息会进入队列等待
474
+ * @param {string|Object} message - 消息
475
+ * @param {Object} options - 选项 { maxSteps }
476
+ * @returns {Promise<{success: boolean, message: string, stepCount: number}>}
477
+ */
478
+ async pushMessage(message, options = {}) {
479
+ // 自动从执行上下文获取 sessionId
480
+ const ctx = this.framework.getExecutionContext()
481
+ if (ctx?.sessionId && !options.sessionId) {
482
+ options.sessionId = ctx.sessionId
483
+ }
484
+
485
+ // 如果忙碌,进入队列等待
486
+ if (this._status === 'busy') {
487
+ const queuedItem = { message, options, resolve: null, reject: null }
488
+ const promise = new Promise((resolve, reject) => {
489
+ queuedItem.resolve = resolve
490
+ queuedItem.reject = reject
491
+ })
492
+ this._messageQueue.push(queuedItem)
493
+ console.log('[Agent] busy, message queued')
494
+ return promise
495
+ }
496
+
497
+ // 空闲则直接处理
498
+ return this.chat(message, options)
499
+ }
500
+
501
+ /**
502
+ * 处理消息队列
503
+ * @private
504
+ */
505
+ async _processQueue() {
506
+ if (this._isProcessingQueue || this._messageQueue.length === 0) {
507
+ return
508
+ }
509
+
510
+ this._isProcessingQueue = true
511
+
512
+ // 强制设置为 idle,确保 this.chat() 能执行
513
+ this._status = 'idle'
514
+
515
+ while (this._messageQueue.length > 0) {
516
+ const item = this._messageQueue.shift()
517
+ try {
518
+ const result = await this.chat(item.message, item.options)
519
+ item.resolve(result)
520
+ } catch (err) {
521
+ item.reject(err)
522
+ }
523
+ }
524
+
525
+ this._isProcessingQueue = false
526
+ }
527
+
458
528
  /**
459
529
  * 发送消息(流式)
460
530
  */
@@ -484,9 +554,16 @@ class Agent extends EventEmitter {
484
554
  yield* this._chatHandler.chatStream(enhancedMessage, options)
485
555
  this._status = 'idle'
486
556
  this.emit('status', { status: 'idle' })
557
+
558
+ // 处理队列中的下一条消息
559
+ setImmediate(() => this._processQueue())
487
560
  } catch (err) {
488
561
  this._status = 'error'
489
562
  this.emit('status', { status: 'error', error: err.message })
563
+
564
+ // 发生错误时也要处理队列
565
+ setImmediate(() => this._processQueue())
566
+
490
567
  throw err
491
568
  }
492
569
  }
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  const path = require('path')
7
+ const { AsyncLocalStorage } = require('async_hooks')
7
8
  const { EventEmitter } = require('../utils/event-emitter')
8
9
  const { PluginManager } = require('./plugin-manager')
9
10
  const { ToolRegistry } = require('./tool-registry')
@@ -16,6 +17,9 @@ if (!module.paths.includes(frameworkNodeModules)) {
16
17
  module.paths.unshift(frameworkNodeModules)
17
18
  }
18
19
 
20
+ // AsyncLocalStorage 实现真正的上下文隔离(支持并行处理)
21
+ const asyncLocalStorage = new AsyncLocalStorage()
22
+
19
23
  class Framework extends EventEmitter {
20
24
  /**
21
25
  * @param {Object} config - 配置
@@ -37,6 +41,9 @@ class Framework extends EventEmitter {
37
41
  this._agents = [] // 所有创建的 agent
38
42
  this._mainAgent = null // 主 agent
39
43
 
44
+ // 执行上下文(工具调用时可用)
45
+ this._executionContext = null
46
+
40
47
  // 事件转发
41
48
  this.toolRegistry.on('tool:registered', (tool) => {
42
49
  this.emit('tool:registered', tool)
@@ -142,6 +149,34 @@ class Framework extends EventEmitter {
142
149
  return this.toolRegistry.execute(name, args, this)
143
150
  }
144
151
 
152
+ /**
153
+ * 在上下文中执行函数(支持并行处理,自动隔离 session)
154
+ * @param {Object} context - 执行上下文 { sessionId, ... }
155
+ * @param {Function} fn - 要执行的异步函数
156
+ * @returns {Promise}
157
+ */
158
+ runWithContext(context, fn) {
159
+ return asyncLocalStorage.run(context, fn)
160
+ }
161
+
162
+ /**
163
+ * 获取当前执行上下文(在 runWithContext 内部调用)
164
+ * @returns {Object|null}
165
+ */
166
+ getExecutionContext() {
167
+ return asyncLocalStorage.getStore() || null
168
+ }
169
+
170
+ /**
171
+ * @deprecated 使用 runWithContext 代替
172
+ */
173
+ setExecutionContext() {}
174
+
175
+ /**
176
+ * @deprecated 使用 runWithContext 代替
177
+ */
178
+ clearExecutionContext() {}
179
+
145
180
  /**
146
181
  * 创建 Agent
147
182
  * @param {Object} config - Agent 配置
@@ -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 ADDED
@@ -0,0 +1,25 @@
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');