foliko 1.0.75 → 1.0.76

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.
Files changed (88) hide show
  1. package/.claude/settings.local.json +159 -157
  2. package/cli/bin/foliko.js +12 -12
  3. package/cli/src/commands/chat.js +143 -143
  4. package/cli/src/commands/list.js +93 -93
  5. package/cli/src/index.js +75 -75
  6. package/cli/src/ui/chat-ui.js +201 -201
  7. package/cli/src/utils/ansi.js +40 -40
  8. package/cli/src/utils/markdown.js +292 -292
  9. package/examples/ambient-example.js +194 -194
  10. package/examples/basic.js +115 -115
  11. package/examples/bootstrap.js +121 -121
  12. package/examples/mcp-example.js +56 -56
  13. package/examples/skill-example.js +49 -49
  14. package/examples/test-chat.js +137 -137
  15. package/examples/test-mcp.js +85 -85
  16. package/examples/test-reload.js +59 -59
  17. package/examples/test-telegram.js +50 -50
  18. package/examples/test-tg-bot.js +45 -45
  19. package/examples/test-tg-simple.js +47 -47
  20. package/examples/test-tg.js +62 -62
  21. package/examples/test-think.js +43 -43
  22. package/examples/test-web-plugin.js +103 -103
  23. package/examples/test-weixin-feishu.js +103 -103
  24. package/examples/workflow.js +158 -158
  25. package/package.json +1 -1
  26. package/plugins/ai-plugin.js +102 -102
  27. package/plugins/ambient-agent/EventWatcher.js +113 -113
  28. package/plugins/ambient-agent/ExplorerLoop.js +640 -640
  29. package/plugins/ambient-agent/GoalManager.js +197 -197
  30. package/plugins/ambient-agent/Reflector.js +95 -95
  31. package/plugins/ambient-agent/StateStore.js +90 -90
  32. package/plugins/ambient-agent/constants.js +101 -101
  33. package/plugins/ambient-agent/index.js +579 -579
  34. package/plugins/audit-plugin.js +187 -187
  35. package/plugins/default-plugins.js +662 -662
  36. package/plugins/email/constants.js +64 -64
  37. package/plugins/email/handlers.js +461 -461
  38. package/plugins/email/index.js +278 -278
  39. package/plugins/email/monitor.js +269 -269
  40. package/plugins/email/parser.js +138 -138
  41. package/plugins/email/reply.js +151 -151
  42. package/plugins/email/utils.js +124 -124
  43. package/plugins/feishu-plugin.js +481 -481
  44. package/plugins/file-system-plugin.js +826 -826
  45. package/plugins/install-plugin.js +199 -199
  46. package/plugins/python-executor-plugin.js +367 -367
  47. package/plugins/python-plugin-loader.js +481 -481
  48. package/plugins/rules-plugin.js +294 -294
  49. package/plugins/scheduler-plugin.js +691 -691
  50. package/plugins/session-plugin.js +369 -369
  51. package/plugins/shell-executor-plugin.js +197 -197
  52. package/plugins/storage-plugin.js +240 -240
  53. package/plugins/subagent-plugin.js +845 -845
  54. package/plugins/telegram-plugin.js +482 -482
  55. package/plugins/think-plugin.js +345 -345
  56. package/plugins/tools-plugin.js +196 -196
  57. package/plugins/web-plugin.js +606 -606
  58. package/plugins/weixin-plugin.js +545 -545
  59. package/src/capabilities/index.js +11 -11
  60. package/src/capabilities/skill-manager.js +609 -609
  61. package/src/capabilities/workflow-engine.js +1109 -1109
  62. package/src/core/agent-chat.js +882 -882
  63. package/src/core/agent.js +892 -892
  64. package/src/core/framework.js +465 -465
  65. package/src/core/index.js +19 -19
  66. package/src/core/plugin-base.js +219 -219
  67. package/src/core/plugin-manager.js +863 -863
  68. package/src/core/provider.js +114 -114
  69. package/src/core/sub-agent-config.js +264 -264
  70. package/src/core/system-prompt-builder.js +120 -120
  71. package/src/core/tool-registry.js +517 -517
  72. package/src/core/tool-router.js +297 -297
  73. package/src/executors/executor-base.js +58 -58
  74. package/src/executors/mcp-executor.js +741 -741
  75. package/src/index.js +25 -25
  76. package/src/utils/circuit-breaker.js +301 -301
  77. package/src/utils/error-boundary.js +363 -363
  78. package/src/utils/error.js +374 -374
  79. package/src/utils/event-emitter.js +97 -97
  80. package/src/utils/id.js +133 -133
  81. package/src/utils/index.js +217 -217
  82. package/src/utils/logger.js +181 -181
  83. package/src/utils/plugin-helpers.js +90 -90
  84. package/src/utils/retry.js +122 -122
  85. package/src/utils/sandbox.js +292 -292
  86. package/test/tool-registry-validation.test.js +218 -218
  87. package/website/script.js +136 -136
  88. package/foliko-1.0.75.tgz +0 -0
@@ -1,579 +1,579 @@
1
- /**
2
- * Ambient Agent 插件
3
- * 持续后台运行的智能代理,监控事件并主动执行操作
4
- */
5
-
6
- const { Plugin } = require('../../src/core/plugin-base')
7
- const { logger } = require('../../src/utils/logger')
8
- const { z } = require('zod')
9
-
10
- // 导入子模块
11
- const { GoalState } = require('./constants')
12
- const { StateStore } = require('./StateStore')
13
- const { GoalManager } = require('./GoalManager')
14
- const { EventWatcher } = require('./EventWatcher')
15
- const { Reflector } = require('./Reflector')
16
- const { ExplorerLoop } = require('./ExplorerLoop')
17
-
18
- const log = logger.child('Ambient')
19
-
20
- class AmbientAgentPlugin extends Plugin {
21
- constructor(config = {}) {
22
- super()
23
- this.name = 'ambient'
24
- this.version = '1.0.0'
25
- this.description = `Ambient Agent - 持续后台运行的智能代理,用于主动监控事件并执行操作
26
-
27
- ## 支持的事件类型(创建目标时 conditions.events 必须使用这些确切的名称):
28
- - email:received - 收到新邮件(参数:from, subject, text, messageId)
29
- - tool:result - 工具执行完成(参数:name, args, result)
30
- - scheduler:reminder - 定时提醒(参数:taskId, message, time)
31
- - scheduler:task_completed - 任务完成(参数:taskId, result)
32
- - scheduler:task_failed - 任务失败(参数:taskId, error)
33
- - agent:message - 代理消息(参数:content, sessionId)
34
- - think:thought_completed - 思考完成(参数:mode, topic, thought)
35
- - webhook:received - Webhook接收(参数:headers, body, query, path)
36
-
37
- ## 在 action 参数中引用事件数据:
38
- 使用 \${event.xxx} 语法,例如:\${event.from}、\${event.subject}、\${event.text}`
39
- this.priority = 18
40
- this.system = true
41
-
42
- this.config = {
43
- enabled: config.enabled !== false,
44
- tickInterval: config.tickInterval || 5000, // tick间隔(毫秒)
45
- cooldownPeriod: config.cooldownPeriod || 3000, // 冷却时间(毫秒)
46
- persistencePath: config.persistencePath || '.agent/data/ambient',
47
- defaultGoals: config.defaultGoals || []
48
- }
49
-
50
- this._framework = null
51
- this._stateStore = null
52
- this._goalManager = null
53
- this._eventWatcher = null
54
- this._reflector = null
55
- this._explorerLoop = null
56
- this._memories = []
57
- }
58
-
59
- // ============================================================================
60
- // 生命周期
61
- // ============================================================================
62
-
63
- install(framework) {
64
- this._framework = framework
65
- this._stateStore = new StateStore(this.config.persistencePath)
66
- this._goalManager = new GoalManager(this._stateStore)
67
- this._reflector = new Reflector(this._goalManager)
68
-
69
- // 加载持久化的记忆
70
- this._memories = this._stateStore.loadMemories()
71
-
72
- return this
73
- }
74
-
75
- start(framework) {
76
- if (!this.config.enabled) {
77
- log.info('插件已禁用,跳过启动')
78
- return this
79
- }
80
-
81
- // 如果没有现有目标,创建默认目标
82
- if (this._goalManager.getAllGoals().length === 0 && this.config.defaultGoals.length > 0) {
83
- for (const goalDef of this.config.defaultGoals) {
84
- this._goalManager.createGoal(goalDef)
85
- }
86
- }
87
-
88
- // 启动事件监听器
89
- this._eventWatcher = new EventWatcher(this._goalManager, this._framework)
90
- this._eventWatcher.start()
91
-
92
- // 动态更新description显示支持的事件及参数
93
- this._updateDescription()
94
-
95
- // 启动探索循环
96
- this._explorerLoop = new ExplorerLoop(this._goalManager, this._reflector, this._framework, {
97
- tickInterval: this.config.tickInterval,
98
- cooldownPeriod: this.config.cooldownPeriod
99
- })
100
- this._explorerLoop.start()
101
-
102
- // 注册工具
103
- this._registerTools(framework)
104
-
105
- log.info('插件已启动')
106
- return this
107
- }
108
-
109
- reload(framework) {
110
- this._framework = framework
111
- if (this._explorerLoop && this._explorerLoop.isRunning()) {
112
- // 用新的框架引用重新启动
113
- this._eventWatcher = new EventWatcher(this._goalManager, this._framework)
114
- this._eventWatcher.start()
115
- }
116
- }
117
-
118
- uninstall(framework) {
119
- // 停止探索循环
120
- if (this._explorerLoop) {
121
- this._explorerLoop.stop()
122
- this._explorerLoop = null
123
- }
124
-
125
- // 停止事件监听器
126
- if (this._eventWatcher) {
127
- this._eventWatcher.stop()
128
- this._eventWatcher = null
129
- }
130
-
131
- // 清除引用
132
- this._framework = null
133
- this._goalManager = null
134
- this._reflector = null
135
- this._stateStore = null
136
- this._memories = []
137
- }
138
-
139
- // ============================================================================
140
- // 描述更新
141
- // ============================================================================
142
-
143
- /**
144
- * 动态更新插件描述,从 Framework 获取已注册的事件描述
145
- */
146
- _updateDescription() {
147
- if (!this._framework) return
148
-
149
- // 从 Framework 获取所有已注册的事件描述
150
- const eventDescriptions = this._framework.getEventDescriptions()
151
-
152
- if (eventDescriptions.size === 0) {
153
- // 如果没有动态注册的事件,使用默认事件列表
154
- const defaultEvents = [
155
- { type: 'tool:result', desc: '工具执行结果 - name, args, result, error' },
156
- { type: 'scheduler:reminder', desc: '定时提醒 - taskId, message, time' },
157
- { type: 'scheduler:task_completed', desc: '任务完成 - taskId, result' },
158
- { type: 'scheduler:task_failed', desc: '任务失败 - taskId, error' },
159
- { type: 'agent:message', desc: '代理消息 - content, sessionId' },
160
- { type: 'think:thought_completed', desc: '思考完成 - mode, topic, thought, depth' },
161
- { type: 'email:received', desc: '收到邮件 - from, to, subject, text, messageId, timestamp' },
162
- { type: 'webhook:received', desc: 'Webhook接收 - webhook, data, headers, query, path, sessionId, response' }
163
- ]
164
-
165
- const eventList = defaultEvents.map(e => ` - ${e.type} - ${e.desc}`).join('\n')
166
- this.description = `Ambient Agent - 持续后台运行的智能代理,用于主动监控和执行操作
167
-
168
- ## 支持的事件类型(创建目标时 conditions.events 必须使用这些确切的名称):
169
- ${eventList}
170
-
171
- ## 在 action 参数中引用事件数据:
172
- 使用 \${event.xxx} 语法,例如:\${event.from}、\${event.subject}、\${event.text}`
173
- return
174
- }
175
-
176
- // 生成事件列表
177
- const eventList = Array.from(eventDescriptions.entries())
178
- .map(([type, info]) => {
179
- const desc = info.params || info.description || ''
180
- return ` - ${type} - ${desc}`
181
- })
182
- .join('\n')
183
-
184
- this.description = `Ambient Agent - 持续后台运行的智能代理,用于主动监控和执行操作
185
-
186
- ## 支持的事件类型(创建目标时 conditions.events 必须使用这些确切的名称):
187
- ${eventList}
188
-
189
- ## 在 action 参数中引用事件数据:
190
- 使用 \${event.xxx} 语法,例如:\${event.from}、\${event.subject}、\${event.text}
191
-
192
- ---
193
- 💡 提示:事件描述由触发事件的插件动态注册。`
194
- }
195
-
196
- // ============================================================================
197
- // 工具注册
198
- // ============================================================================
199
-
200
- _registerTools(framework) {
201
- // ambient_goals - 列出/创建/更新/删除目标
202
- framework.registerTool({
203
- name: 'ambient_goals',
204
- description: '管理Ambient Agent目标 - 列出、创建、更新、删除、激活目标',
205
- inputSchema: z.object({
206
- action: z.enum(['list', 'create', 'update', 'delete', 'activate']).describe('执行的操作'),
207
- goalId: z.string().optional().describe('目标ID(更新/删除/激活时必需)'),
208
- title: z.string().optional().describe('目标标题(创建/更新时使用)'),
209
- description: z.string().optional().describe('目标描述(创建/更新时使用)'),
210
- priority: z.number().optional().describe('优先级1-10,数值越高越重要(创建/更新时使用)'),
211
- actions: z.array(z.object({
212
- id: z.string().optional().describe('操作标识符'),
213
- type: z.enum(['tool', 'message', 'think']).describe('操作类型'),
214
- name: z.string().optional().describe('工具名称(tool类型时使用)'),
215
- args: z.record(z.any()).optional().describe('工具参数(tool类型时使用)'),
216
- content: z.string().optional().describe('消息内容(message类型时使用)'),
217
- topic: z.string().optional().describe('思考主题(think类型时使用)'),
218
- mode: z.enum(['reflect', 'brainstorm', 'analyze', 'plan']).optional().describe('思考模式(think类型时使用)')
219
- })).optional().describe('要执行的操作列表(创建/更新时使用)'),
220
- conditions: z.object({
221
- events: z.union([z.string(), z.array(z.string())]).optional().describe('要监听的事件类型'),
222
- toolNames: z.union([z.string(), z.array(z.string())]).optional().describe('按工具名称过滤')
223
- }).optional().describe('激活条件(创建/更新时使用)')
224
- }),
225
- execute: async (args) => {
226
- return this._handleGoalsTool(args)
227
- }
228
- })
229
-
230
- // ambient_status - 获取当前循环状态
231
- framework.registerTool({
232
- name: 'ambient_status',
233
- description: '获取当前Ambient Agent状态 - 循环状态、进行中的目标、最近活动',
234
- inputSchema: z.object({}),
235
- execute: async () => {
236
- return this._handleStatusTool()
237
- }
238
- })
239
-
240
- // ambient_think - 触发主动LLM思考
241
- framework.registerTool({
242
- name: 'ambient_think',
243
- description: '为某个目标触发主动LLM思考 - 模式:reflect(反思)、brainstorm(头脑风暴)、plan(计划)、analyze(分析)',
244
- inputSchema: z.object({
245
- goalId: z.string().optional().describe('要思考的目标ID'),
246
- mode: z.enum(['reflect', 'brainstorm', 'plan', 'analyze']).describe('思考模式'),
247
- topic: z.string().optional().describe('要思考的主题'),
248
- depth: z.number().optional().describe('思考深度1-5')
249
- }),
250
- execute: async (args) => {
251
- return this._handleThinkTool(args)
252
- }
253
- })
254
-
255
- // ambient_remember - 存储/检索/搜索持久化记忆
256
- framework.registerTool({
257
- name: 'ambient_remember',
258
- description: '为Ambient Agent存储或检索持久化记忆',
259
- inputSchema: z.object({
260
- action: z.enum(['store', 'retrieve', 'search']).describe('操作:store存储记忆、retrieve检索最近、search搜索'),
261
- content: z.string().optional().describe('记忆内容(store时使用)'),
262
- key: z.string().optional().describe('记忆键(store/retrieve时使用)'),
263
- query: z.string().optional().describe('搜索查询(search时使用)'),
264
- limit: z.number().optional().describe('最大结果数(retrieve/search时使用)')
265
- }),
266
- execute: async (args) => {
267
- return this._handleRememberTool(args)
268
- }
269
- })
270
-
271
- // ambient_control - 暂停/恢复/调整探索循环
272
- framework.registerTool({
273
- name: 'ambient_control',
274
- description: '控制Ambient Agent探索循环 - 暂停、恢复或调整设置',
275
- inputSchema: z.object({
276
- action: z.enum(['pause', 'resume', 'status', 'adjust']).describe('控制操作'),
277
- tickInterval: z.number().optional().describe('新的tick间隔毫秒数(adjust时使用)'),
278
- cooldownPeriod: z.number().optional().describe('新的冷却时间毫秒数(adjust时使用)')
279
- }),
280
- execute: async (args) => {
281
- return this._handleControlTool(args)
282
- }
283
- })
284
- }
285
-
286
- // ============================================================================
287
- // 工具处理器
288
- // ============================================================================
289
-
290
- _handleGoalsTool(args) {
291
- const { action, goalId, title, description, priority, actions, conditions } = args
292
-
293
- switch (action) {
294
- case 'list': {
295
- const allGoals = this._goalManager.getAllGoals()
296
- return {
297
- success: true,
298
- goals: allGoals.map(g => ({
299
- id: g.id,
300
- title: g.title,
301
- state: g.state,
302
- priority: g.priority,
303
- actionsCount: g.actions ? g.actions.length : 0,
304
- attempts: g.attempts,
305
- createdAt: g.createdAt,
306
- activatedAt: g.activatedAt,
307
- completedAt: g.completedAt,
308
- failedAt: g.failedAt
309
- })),
310
- total: allGoals.length,
311
- active: this._goalManager.getActiveGoals().length,
312
- pending: this._goalManager.getPendingGoals().length
313
- }
314
- }
315
-
316
- case 'create': {
317
- if (!title) {
318
- return { success: false, error: '创建目标需要提供标题' }
319
- }
320
- const goal = this._goalManager.createGoal({ title, description, priority, actions, conditions })
321
- return { success: true, goal }
322
- }
323
-
324
- case 'update': {
325
- if (!goalId) {
326
- return { success: false, error: '更新目标需要提供目标ID' }
327
- }
328
- const updates = {}
329
- if (title !== undefined) updates.title = title
330
- if (description !== undefined) updates.description = description
331
- if (priority !== undefined) updates.priority = priority
332
- if (actions !== undefined) updates.actions = actions
333
- if (conditions !== undefined) updates.conditions = conditions
334
- const goal = this._goalManager.updateGoal(goalId, updates)
335
- return goal ? { success: true, goal } : { success: false, error: '目标未找到' }
336
- }
337
-
338
- case 'delete': {
339
- if (!goalId) {
340
- return { success: false, error: '删除目标需要提供目标ID' }
341
- }
342
- const deleted = this._goalManager.deleteGoal(goalId)
343
- return { success: deleted }
344
- }
345
-
346
- case 'activate': {
347
- if (!goalId) {
348
- return { success: false, error: '激活目标需要提供目标ID' }
349
- }
350
- const goal = this._goalManager.activateGoal(goalId)
351
- return goal ? { success: true, goal } : { success: false, error: '目标未找到或不是待激活状态' }
352
- }
353
-
354
- default:
355
- return { success: false, error: `未知操作: ${action}` }
356
- }
357
- }
358
-
359
- _handleStatusTool() {
360
- if (!this._explorerLoop) {
361
- return { success: false, error: '探索循环未初始化' }
362
- }
363
-
364
- const loopStatus = this._explorerLoop.getStatus()
365
- const activeGoals = this._goalManager.getActiveGoals().map(g => ({
366
- id: g.id,
367
- title: g.title,
368
- priority: g.priority,
369
- attempts: g.attempts,
370
- lastActionId: g.lastActionId
371
- }))
372
- const pendingGoals = this._goalManager.getPendingGoals().map(g => ({
373
- id: g.id,
374
- title: g.title,
375
- priority: g.priority
376
- }))
377
-
378
- return {
379
- success: true,
380
- loop: {
381
- running: loopStatus.running,
382
- tickCount: loopStatus.tickCount,
383
- lastTick: loopStatus.lastTick,
384
- tickInterval: this.config.tickInterval,
385
- cooldownPeriod: this.config.cooldownPeriod
386
- },
387
- activeGoals,
388
- pendingGoals,
389
- recentActivities: loopStatus.recentActivities
390
- }
391
- }
392
-
393
- async _handleThinkTool(args) {
394
- const { goalId, mode, topic, depth } = args
395
-
396
- // 获取活跃代理
397
- const agent = this._getActiveAgent()
398
- if (!agent) {
399
- return { success: false, error: '没有可用的活跃代理' }
400
- }
401
-
402
- // 构建思考提示
403
- let prompt = ''
404
- if (goalId) {
405
- const goal = this._goalManager.getGoal(goalId)
406
- if (goal) {
407
- const { ThinkModePrompts } = require('./constants')
408
- const modePrompts = ThinkModePrompts
409
- const modePromptFn = modePrompts[mode]
410
- prompt = modePromptFn ? modePromptFn(goal, topic) : modePrompts.reflect(goal, topic)
411
- } else {
412
- return { success: false, error: '目标未找到' }
413
- }
414
- } else {
415
- const { FreeThinkPrompts } = require('./constants')
416
- const modePrompts = FreeThinkPrompts
417
- const modePromptFn = modePrompts[mode]
418
- prompt = modePromptFn ? modePromptFn(topic) : modePrompts.reflect(topic)
419
- }
420
-
421
- // 如果代理忙,等待其变为可用
422
- let attempts = 0
423
- const maxWaitAttempts = 10
424
- const waitInterval = 500
425
-
426
- while (agent._status === 'busy' && attempts < maxWaitAttempts) {
427
- log.info('代理忙,等待中...')
428
- await new Promise(resolve => setTimeout(resolve, waitInterval))
429
- attempts++
430
- }
431
-
432
- if (agent._status === 'busy') {
433
- return {
434
- success: false,
435
- error: '代理繁忙,无法及时变为可用。请稍后重试。',
436
- queued: true
437
- }
438
- }
439
-
440
- // 通过代理执行思考
441
- const thinkPlugin = this._framework.pluginManager.get('think')
442
- if (thinkPlugin) {
443
- const result = await thinkPlugin._triggerThinking({ topic: prompt, mode, depth: depth || 2 })
444
- // 如果结果提示繁忙,返回更友好的消息
445
- if (result && result.message && result.message.includes && result.message.includes('busy')) {
446
- return {
447
- success: true,
448
- queued: true,
449
- message: '思考请求已排队,将在代理空闲时处理。'
450
- }
451
- }
452
- return result
453
- }
454
-
455
- // 备用:直接推送消息
456
- return agent.pushMessage(prompt).then(result => ({
457
- success: true,
458
- result: typeof result === 'string' ? result : JSON.stringify(result)
459
- })).catch(err => ({
460
- success: false,
461
- error: err.message
462
- }))
463
- }
464
-
465
- _handleRememberTool(args) {
466
- const { action, content, key, query, limit } = args
467
- const maxResults = limit || 10
468
-
469
- switch (action) {
470
- case 'store': {
471
- if (!content) {
472
- return { success: false, error: '存储需要提供内容' }
473
- }
474
- const memoryKey = key || `memory_${Date.now()}`
475
- const memory = {
476
- key: memoryKey,
477
- content,
478
- timestamp: new Date()
479
- }
480
- this._memories.push(memory)
481
- this._stateStore.saveMemories(this._memories)
482
- return { success: true, memory }
483
- }
484
-
485
- case 'retrieve': {
486
- const memories = this._memories.slice(-maxResults).reverse()
487
- return {
488
- success: true,
489
- memories,
490
- total: this._memories.length
491
- }
492
- }
493
-
494
- case 'search': {
495
- if (!query) {
496
- return { success: false, error: '搜索需要提供查询词' }
497
- }
498
- const queryLower = query.toLowerCase()
499
- const results = this._memories
500
- .filter(m => m.content.toLowerCase().includes(queryLower))
501
- .slice(-maxResults)
502
- .reverse()
503
- return {
504
- success: true,
505
- results,
506
- total: results.length
507
- }
508
- }
509
-
510
- default:
511
- return { success: false, error: `未知操作: ${action}` }
512
- }
513
- }
514
-
515
- _handleControlTool(args) {
516
- const { action, tickInterval, cooldownPeriod } = args
517
-
518
- switch (action) {
519
- case 'pause': {
520
- if (!this._explorerLoop) {
521
- return { success: false, error: '探索循环未初始化' }
522
- }
523
- this._explorerLoop.pause()
524
- return { success: true, message: '探索循环已暂停' }
525
- }
526
-
527
- case 'resume': {
528
- if (!this._explorerLoop) {
529
- return { success: false, error: '探索循环未初始化' }
530
- }
531
- this._explorerLoop.resume()
532
- return { success: true, message: '探索循环已恢复' }
533
- }
534
-
535
- case 'status': {
536
- if (!this._explorerLoop) {
537
- return { success: false, error: '探索循环未初始化' }
538
- }
539
- const status = this._explorerLoop.getStatus()
540
- return {
541
- success: true,
542
- running: status.running,
543
- tickCount: status.tickCount,
544
- lastTick: status.lastTick,
545
- tickInterval: this.config.tickInterval,
546
- cooldownPeriod: this.config.cooldownPeriod
547
- }
548
- }
549
-
550
- case 'adjust': {
551
- if (tickInterval) {
552
- this.config.tickInterval = tickInterval
553
- }
554
- if (cooldownPeriod) {
555
- this.config.cooldownPeriod = cooldownPeriod
556
- }
557
- return {
558
- success: true,
559
- message: '设置已调整',
560
- tickInterval: this.config.tickInterval,
561
- cooldownPeriod: this.config.cooldownPeriod
562
- }
563
- }
564
-
565
- default:
566
- return { success: false, error: `未知操作: ${action}` }
567
- }
568
- }
569
-
570
- _getActiveAgent() {
571
- if (this._framework._mainAgent) {
572
- return this._framework._mainAgent
573
- }
574
- const agents = this._framework._agents || []
575
- return agents.length > 0 ? agents[agents.length - 1] : null
576
- }
577
- }
578
-
579
- module.exports = { AmbientAgentPlugin, GoalState }
1
+ /**
2
+ * Ambient Agent 插件
3
+ * 持续后台运行的智能代理,监控事件并主动执行操作
4
+ */
5
+
6
+ const { Plugin } = require('../../src/core/plugin-base')
7
+ const { logger } = require('../../src/utils/logger')
8
+ const { z } = require('zod')
9
+
10
+ // 导入子模块
11
+ const { GoalState } = require('./constants')
12
+ const { StateStore } = require('./StateStore')
13
+ const { GoalManager } = require('./GoalManager')
14
+ const { EventWatcher } = require('./EventWatcher')
15
+ const { Reflector } = require('./Reflector')
16
+ const { ExplorerLoop } = require('./ExplorerLoop')
17
+
18
+ const log = logger.child('Ambient')
19
+
20
+ class AmbientAgentPlugin extends Plugin {
21
+ constructor(config = {}) {
22
+ super()
23
+ this.name = 'ambient'
24
+ this.version = '1.0.0'
25
+ this.description = `Ambient Agent - 持续后台运行的智能代理,用于主动监控事件并执行操作
26
+
27
+ ## 支持的事件类型(创建目标时 conditions.events 必须使用这些确切的名称):
28
+ - email:received - 收到新邮件(参数:from, subject, text, messageId)
29
+ - tool:result - 工具执行完成(参数:name, args, result)
30
+ - scheduler:reminder - 定时提醒(参数:taskId, message, time)
31
+ - scheduler:task_completed - 任务完成(参数:taskId, result)
32
+ - scheduler:task_failed - 任务失败(参数:taskId, error)
33
+ - agent:message - 代理消息(参数:content, sessionId)
34
+ - think:thought_completed - 思考完成(参数:mode, topic, thought)
35
+ - webhook:received - Webhook接收(参数:headers, body, query, path)
36
+
37
+ ## 在 action 参数中引用事件数据:
38
+ 使用 \${event.xxx} 语法,例如:\${event.from}、\${event.subject}、\${event.text}`
39
+ this.priority = 18
40
+ this.system = true
41
+
42
+ this.config = {
43
+ enabled: config.enabled !== false,
44
+ tickInterval: config.tickInterval || 5000, // tick间隔(毫秒)
45
+ cooldownPeriod: config.cooldownPeriod || 3000, // 冷却时间(毫秒)
46
+ persistencePath: config.persistencePath || '.agent/data/ambient',
47
+ defaultGoals: config.defaultGoals || []
48
+ }
49
+
50
+ this._framework = null
51
+ this._stateStore = null
52
+ this._goalManager = null
53
+ this._eventWatcher = null
54
+ this._reflector = null
55
+ this._explorerLoop = null
56
+ this._memories = []
57
+ }
58
+
59
+ // ============================================================================
60
+ // 生命周期
61
+ // ============================================================================
62
+
63
+ install(framework) {
64
+ this._framework = framework
65
+ this._stateStore = new StateStore(this.config.persistencePath)
66
+ this._goalManager = new GoalManager(this._stateStore)
67
+ this._reflector = new Reflector(this._goalManager)
68
+
69
+ // 加载持久化的记忆
70
+ this._memories = this._stateStore.loadMemories()
71
+
72
+ return this
73
+ }
74
+
75
+ start(framework) {
76
+ if (!this.config.enabled) {
77
+ log.info('插件已禁用,跳过启动')
78
+ return this
79
+ }
80
+
81
+ // 如果没有现有目标,创建默认目标
82
+ if (this._goalManager.getAllGoals().length === 0 && this.config.defaultGoals.length > 0) {
83
+ for (const goalDef of this.config.defaultGoals) {
84
+ this._goalManager.createGoal(goalDef)
85
+ }
86
+ }
87
+
88
+ // 启动事件监听器
89
+ this._eventWatcher = new EventWatcher(this._goalManager, this._framework)
90
+ this._eventWatcher.start()
91
+
92
+ // 动态更新description显示支持的事件及参数
93
+ this._updateDescription()
94
+
95
+ // 启动探索循环
96
+ this._explorerLoop = new ExplorerLoop(this._goalManager, this._reflector, this._framework, {
97
+ tickInterval: this.config.tickInterval,
98
+ cooldownPeriod: this.config.cooldownPeriod
99
+ })
100
+ this._explorerLoop.start()
101
+
102
+ // 注册工具
103
+ this._registerTools(framework)
104
+
105
+ log.info('插件已启动')
106
+ return this
107
+ }
108
+
109
+ reload(framework) {
110
+ this._framework = framework
111
+ if (this._explorerLoop && this._explorerLoop.isRunning()) {
112
+ // 用新的框架引用重新启动
113
+ this._eventWatcher = new EventWatcher(this._goalManager, this._framework)
114
+ this._eventWatcher.start()
115
+ }
116
+ }
117
+
118
+ uninstall(framework) {
119
+ // 停止探索循环
120
+ if (this._explorerLoop) {
121
+ this._explorerLoop.stop()
122
+ this._explorerLoop = null
123
+ }
124
+
125
+ // 停止事件监听器
126
+ if (this._eventWatcher) {
127
+ this._eventWatcher.stop()
128
+ this._eventWatcher = null
129
+ }
130
+
131
+ // 清除引用
132
+ this._framework = null
133
+ this._goalManager = null
134
+ this._reflector = null
135
+ this._stateStore = null
136
+ this._memories = []
137
+ }
138
+
139
+ // ============================================================================
140
+ // 描述更新
141
+ // ============================================================================
142
+
143
+ /**
144
+ * 动态更新插件描述,从 Framework 获取已注册的事件描述
145
+ */
146
+ _updateDescription() {
147
+ if (!this._framework) return
148
+
149
+ // 从 Framework 获取所有已注册的事件描述
150
+ const eventDescriptions = this._framework.getEventDescriptions()
151
+
152
+ if (eventDescriptions.size === 0) {
153
+ // 如果没有动态注册的事件,使用默认事件列表
154
+ const defaultEvents = [
155
+ { type: 'tool:result', desc: '工具执行结果 - name, args, result, error' },
156
+ { type: 'scheduler:reminder', desc: '定时提醒 - taskId, message, time' },
157
+ { type: 'scheduler:task_completed', desc: '任务完成 - taskId, result' },
158
+ { type: 'scheduler:task_failed', desc: '任务失败 - taskId, error' },
159
+ { type: 'agent:message', desc: '代理消息 - content, sessionId' },
160
+ { type: 'think:thought_completed', desc: '思考完成 - mode, topic, thought, depth' },
161
+ { type: 'email:received', desc: '收到邮件 - from, to, subject, text, messageId, timestamp' },
162
+ { type: 'webhook:received', desc: 'Webhook接收 - webhook, data, headers, query, path, sessionId, response' }
163
+ ]
164
+
165
+ const eventList = defaultEvents.map(e => ` - ${e.type} - ${e.desc}`).join('\n')
166
+ this.description = `Ambient Agent - 持续后台运行的智能代理,用于主动监控和执行操作
167
+
168
+ ## 支持的事件类型(创建目标时 conditions.events 必须使用这些确切的名称):
169
+ ${eventList}
170
+
171
+ ## 在 action 参数中引用事件数据:
172
+ 使用 \${event.xxx} 语法,例如:\${event.from}、\${event.subject}、\${event.text}`
173
+ return
174
+ }
175
+
176
+ // 生成事件列表
177
+ const eventList = Array.from(eventDescriptions.entries())
178
+ .map(([type, info]) => {
179
+ const desc = info.params || info.description || ''
180
+ return ` - ${type} - ${desc}`
181
+ })
182
+ .join('\n')
183
+
184
+ this.description = `Ambient Agent - 持续后台运行的智能代理,用于主动监控和执行操作
185
+
186
+ ## 支持的事件类型(创建目标时 conditions.events 必须使用这些确切的名称):
187
+ ${eventList}
188
+
189
+ ## 在 action 参数中引用事件数据:
190
+ 使用 \${event.xxx} 语法,例如:\${event.from}、\${event.subject}、\${event.text}
191
+
192
+ ---
193
+ 💡 提示:事件描述由触发事件的插件动态注册。`
194
+ }
195
+
196
+ // ============================================================================
197
+ // 工具注册
198
+ // ============================================================================
199
+
200
+ _registerTools(framework) {
201
+ // ambient_goals - 列出/创建/更新/删除目标
202
+ framework.registerTool({
203
+ name: 'ambient_goals',
204
+ description: '管理Ambient Agent目标 - 列出、创建、更新、删除、激活目标',
205
+ inputSchema: z.object({
206
+ action: z.enum(['list', 'create', 'update', 'delete', 'activate']).describe('执行的操作'),
207
+ goalId: z.string().optional().describe('目标ID(更新/删除/激活时必需)'),
208
+ title: z.string().optional().describe('目标标题(创建/更新时使用)'),
209
+ description: z.string().optional().describe('目标描述(创建/更新时使用)'),
210
+ priority: z.number().optional().describe('优先级1-10,数值越高越重要(创建/更新时使用)'),
211
+ actions: z.array(z.object({
212
+ id: z.string().optional().describe('操作标识符'),
213
+ type: z.enum(['tool', 'message', 'think']).describe('操作类型'),
214
+ name: z.string().optional().describe('工具名称(tool类型时使用)'),
215
+ args: z.record(z.any()).optional().describe('工具参数(tool类型时使用)'),
216
+ content: z.string().optional().describe('消息内容(message类型时使用)'),
217
+ topic: z.string().optional().describe('思考主题(think类型时使用)'),
218
+ mode: z.enum(['reflect', 'brainstorm', 'analyze', 'plan']).optional().describe('思考模式(think类型时使用)')
219
+ })).optional().describe('要执行的操作列表(创建/更新时使用)'),
220
+ conditions: z.object({
221
+ events: z.union([z.string(), z.array(z.string())]).optional().describe('要监听的事件类型'),
222
+ toolNames: z.union([z.string(), z.array(z.string())]).optional().describe('按工具名称过滤')
223
+ }).optional().describe('激活条件(创建/更新时使用)')
224
+ }),
225
+ execute: async (args) => {
226
+ return this._handleGoalsTool(args)
227
+ }
228
+ })
229
+
230
+ // ambient_status - 获取当前循环状态
231
+ framework.registerTool({
232
+ name: 'ambient_status',
233
+ description: '获取当前Ambient Agent状态 - 循环状态、进行中的目标、最近活动',
234
+ inputSchema: z.object({}),
235
+ execute: async () => {
236
+ return this._handleStatusTool()
237
+ }
238
+ })
239
+
240
+ // ambient_think - 触发主动LLM思考
241
+ framework.registerTool({
242
+ name: 'ambient_think',
243
+ description: '为某个目标触发主动LLM思考 - 模式:reflect(反思)、brainstorm(头脑风暴)、plan(计划)、analyze(分析)',
244
+ inputSchema: z.object({
245
+ goalId: z.string().optional().describe('要思考的目标ID'),
246
+ mode: z.enum(['reflect', 'brainstorm', 'plan', 'analyze']).describe('思考模式'),
247
+ topic: z.string().optional().describe('要思考的主题'),
248
+ depth: z.number().optional().describe('思考深度1-5')
249
+ }),
250
+ execute: async (args) => {
251
+ return this._handleThinkTool(args)
252
+ }
253
+ })
254
+
255
+ // ambient_remember - 存储/检索/搜索持久化记忆
256
+ framework.registerTool({
257
+ name: 'ambient_remember',
258
+ description: '为Ambient Agent存储或检索持久化记忆',
259
+ inputSchema: z.object({
260
+ action: z.enum(['store', 'retrieve', 'search']).describe('操作:store存储记忆、retrieve检索最近、search搜索'),
261
+ content: z.string().optional().describe('记忆内容(store时使用)'),
262
+ key: z.string().optional().describe('记忆键(store/retrieve时使用)'),
263
+ query: z.string().optional().describe('搜索查询(search时使用)'),
264
+ limit: z.number().optional().describe('最大结果数(retrieve/search时使用)')
265
+ }),
266
+ execute: async (args) => {
267
+ return this._handleRememberTool(args)
268
+ }
269
+ })
270
+
271
+ // ambient_control - 暂停/恢复/调整探索循环
272
+ framework.registerTool({
273
+ name: 'ambient_control',
274
+ description: '控制Ambient Agent探索循环 - 暂停、恢复或调整设置',
275
+ inputSchema: z.object({
276
+ action: z.enum(['pause', 'resume', 'status', 'adjust']).describe('控制操作'),
277
+ tickInterval: z.number().optional().describe('新的tick间隔毫秒数(adjust时使用)'),
278
+ cooldownPeriod: z.number().optional().describe('新的冷却时间毫秒数(adjust时使用)')
279
+ }),
280
+ execute: async (args) => {
281
+ return this._handleControlTool(args)
282
+ }
283
+ })
284
+ }
285
+
286
+ // ============================================================================
287
+ // 工具处理器
288
+ // ============================================================================
289
+
290
+ _handleGoalsTool(args) {
291
+ const { action, goalId, title, description, priority, actions, conditions } = args
292
+
293
+ switch (action) {
294
+ case 'list': {
295
+ const allGoals = this._goalManager.getAllGoals()
296
+ return {
297
+ success: true,
298
+ goals: allGoals.map(g => ({
299
+ id: g.id,
300
+ title: g.title,
301
+ state: g.state,
302
+ priority: g.priority,
303
+ actionsCount: g.actions ? g.actions.length : 0,
304
+ attempts: g.attempts,
305
+ createdAt: g.createdAt,
306
+ activatedAt: g.activatedAt,
307
+ completedAt: g.completedAt,
308
+ failedAt: g.failedAt
309
+ })),
310
+ total: allGoals.length,
311
+ active: this._goalManager.getActiveGoals().length,
312
+ pending: this._goalManager.getPendingGoals().length
313
+ }
314
+ }
315
+
316
+ case 'create': {
317
+ if (!title) {
318
+ return { success: false, error: '创建目标需要提供标题' }
319
+ }
320
+ const goal = this._goalManager.createGoal({ title, description, priority, actions, conditions })
321
+ return { success: true, goal }
322
+ }
323
+
324
+ case 'update': {
325
+ if (!goalId) {
326
+ return { success: false, error: '更新目标需要提供目标ID' }
327
+ }
328
+ const updates = {}
329
+ if (title !== undefined) updates.title = title
330
+ if (description !== undefined) updates.description = description
331
+ if (priority !== undefined) updates.priority = priority
332
+ if (actions !== undefined) updates.actions = actions
333
+ if (conditions !== undefined) updates.conditions = conditions
334
+ const goal = this._goalManager.updateGoal(goalId, updates)
335
+ return goal ? { success: true, goal } : { success: false, error: '目标未找到' }
336
+ }
337
+
338
+ case 'delete': {
339
+ if (!goalId) {
340
+ return { success: false, error: '删除目标需要提供目标ID' }
341
+ }
342
+ const deleted = this._goalManager.deleteGoal(goalId)
343
+ return { success: deleted }
344
+ }
345
+
346
+ case 'activate': {
347
+ if (!goalId) {
348
+ return { success: false, error: '激活目标需要提供目标ID' }
349
+ }
350
+ const goal = this._goalManager.activateGoal(goalId)
351
+ return goal ? { success: true, goal } : { success: false, error: '目标未找到或不是待激活状态' }
352
+ }
353
+
354
+ default:
355
+ return { success: false, error: `未知操作: ${action}` }
356
+ }
357
+ }
358
+
359
+ _handleStatusTool() {
360
+ if (!this._explorerLoop) {
361
+ return { success: false, error: '探索循环未初始化' }
362
+ }
363
+
364
+ const loopStatus = this._explorerLoop.getStatus()
365
+ const activeGoals = this._goalManager.getActiveGoals().map(g => ({
366
+ id: g.id,
367
+ title: g.title,
368
+ priority: g.priority,
369
+ attempts: g.attempts,
370
+ lastActionId: g.lastActionId
371
+ }))
372
+ const pendingGoals = this._goalManager.getPendingGoals().map(g => ({
373
+ id: g.id,
374
+ title: g.title,
375
+ priority: g.priority
376
+ }))
377
+
378
+ return {
379
+ success: true,
380
+ loop: {
381
+ running: loopStatus.running,
382
+ tickCount: loopStatus.tickCount,
383
+ lastTick: loopStatus.lastTick,
384
+ tickInterval: this.config.tickInterval,
385
+ cooldownPeriod: this.config.cooldownPeriod
386
+ },
387
+ activeGoals,
388
+ pendingGoals,
389
+ recentActivities: loopStatus.recentActivities
390
+ }
391
+ }
392
+
393
+ async _handleThinkTool(args) {
394
+ const { goalId, mode, topic, depth } = args
395
+
396
+ // 获取活跃代理
397
+ const agent = this._getActiveAgent()
398
+ if (!agent) {
399
+ return { success: false, error: '没有可用的活跃代理' }
400
+ }
401
+
402
+ // 构建思考提示
403
+ let prompt = ''
404
+ if (goalId) {
405
+ const goal = this._goalManager.getGoal(goalId)
406
+ if (goal) {
407
+ const { ThinkModePrompts } = require('./constants')
408
+ const modePrompts = ThinkModePrompts
409
+ const modePromptFn = modePrompts[mode]
410
+ prompt = modePromptFn ? modePromptFn(goal, topic) : modePrompts.reflect(goal, topic)
411
+ } else {
412
+ return { success: false, error: '目标未找到' }
413
+ }
414
+ } else {
415
+ const { FreeThinkPrompts } = require('./constants')
416
+ const modePrompts = FreeThinkPrompts
417
+ const modePromptFn = modePrompts[mode]
418
+ prompt = modePromptFn ? modePromptFn(topic) : modePrompts.reflect(topic)
419
+ }
420
+
421
+ // 如果代理忙,等待其变为可用
422
+ let attempts = 0
423
+ const maxWaitAttempts = 10
424
+ const waitInterval = 500
425
+
426
+ while (agent._status === 'busy' && attempts < maxWaitAttempts) {
427
+ log.info('代理忙,等待中...')
428
+ await new Promise(resolve => setTimeout(resolve, waitInterval))
429
+ attempts++
430
+ }
431
+
432
+ if (agent._status === 'busy') {
433
+ return {
434
+ success: false,
435
+ error: '代理繁忙,无法及时变为可用。请稍后重试。',
436
+ queued: true
437
+ }
438
+ }
439
+
440
+ // 通过代理执行思考
441
+ const thinkPlugin = this._framework.pluginManager.get('think')
442
+ if (thinkPlugin) {
443
+ const result = await thinkPlugin._triggerThinking({ topic: prompt, mode, depth: depth || 2 })
444
+ // 如果结果提示繁忙,返回更友好的消息
445
+ if (result && result.message && result.message.includes && result.message.includes('busy')) {
446
+ return {
447
+ success: true,
448
+ queued: true,
449
+ message: '思考请求已排队,将在代理空闲时处理。'
450
+ }
451
+ }
452
+ return result
453
+ }
454
+
455
+ // 备用:直接推送消息
456
+ return agent.pushMessage(prompt).then(result => ({
457
+ success: true,
458
+ result: typeof result === 'string' ? result : JSON.stringify(result)
459
+ })).catch(err => ({
460
+ success: false,
461
+ error: err.message
462
+ }))
463
+ }
464
+
465
+ _handleRememberTool(args) {
466
+ const { action, content, key, query, limit } = args
467
+ const maxResults = limit || 10
468
+
469
+ switch (action) {
470
+ case 'store': {
471
+ if (!content) {
472
+ return { success: false, error: '存储需要提供内容' }
473
+ }
474
+ const memoryKey = key || `memory_${Date.now()}`
475
+ const memory = {
476
+ key: memoryKey,
477
+ content,
478
+ timestamp: new Date()
479
+ }
480
+ this._memories.push(memory)
481
+ this._stateStore.saveMemories(this._memories)
482
+ return { success: true, memory }
483
+ }
484
+
485
+ case 'retrieve': {
486
+ const memories = this._memories.slice(-maxResults).reverse()
487
+ return {
488
+ success: true,
489
+ memories,
490
+ total: this._memories.length
491
+ }
492
+ }
493
+
494
+ case 'search': {
495
+ if (!query) {
496
+ return { success: false, error: '搜索需要提供查询词' }
497
+ }
498
+ const queryLower = query.toLowerCase()
499
+ const results = this._memories
500
+ .filter(m => m.content.toLowerCase().includes(queryLower))
501
+ .slice(-maxResults)
502
+ .reverse()
503
+ return {
504
+ success: true,
505
+ results,
506
+ total: results.length
507
+ }
508
+ }
509
+
510
+ default:
511
+ return { success: false, error: `未知操作: ${action}` }
512
+ }
513
+ }
514
+
515
+ _handleControlTool(args) {
516
+ const { action, tickInterval, cooldownPeriod } = args
517
+
518
+ switch (action) {
519
+ case 'pause': {
520
+ if (!this._explorerLoop) {
521
+ return { success: false, error: '探索循环未初始化' }
522
+ }
523
+ this._explorerLoop.pause()
524
+ return { success: true, message: '探索循环已暂停' }
525
+ }
526
+
527
+ case 'resume': {
528
+ if (!this._explorerLoop) {
529
+ return { success: false, error: '探索循环未初始化' }
530
+ }
531
+ this._explorerLoop.resume()
532
+ return { success: true, message: '探索循环已恢复' }
533
+ }
534
+
535
+ case 'status': {
536
+ if (!this._explorerLoop) {
537
+ return { success: false, error: '探索循环未初始化' }
538
+ }
539
+ const status = this._explorerLoop.getStatus()
540
+ return {
541
+ success: true,
542
+ running: status.running,
543
+ tickCount: status.tickCount,
544
+ lastTick: status.lastTick,
545
+ tickInterval: this.config.tickInterval,
546
+ cooldownPeriod: this.config.cooldownPeriod
547
+ }
548
+ }
549
+
550
+ case 'adjust': {
551
+ if (tickInterval) {
552
+ this.config.tickInterval = tickInterval
553
+ }
554
+ if (cooldownPeriod) {
555
+ this.config.cooldownPeriod = cooldownPeriod
556
+ }
557
+ return {
558
+ success: true,
559
+ message: '设置已调整',
560
+ tickInterval: this.config.tickInterval,
561
+ cooldownPeriod: this.config.cooldownPeriod
562
+ }
563
+ }
564
+
565
+ default:
566
+ return { success: false, error: `未知操作: ${action}` }
567
+ }
568
+ }
569
+
570
+ _getActiveAgent() {
571
+ if (this._framework._mainAgent) {
572
+ return this._framework._mainAgent
573
+ }
574
+ const agents = this._framework._agents || []
575
+ return agents.length > 0 ? agents[agents.length - 1] : null
576
+ }
577
+ }
578
+
579
+ module.exports = { AmbientAgentPlugin, GoalState }