foliko 1.0.74 → 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 (238) hide show
  1. package/.agent/.shared/ui-ux-pro-max/data/charts.csv +26 -0
  2. package/.agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
  3. package/.agent/.shared/ui-ux-pro-max/data/icons.csv +101 -0
  4. package/.agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
  5. package/.agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
  6. package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
  7. package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +45 -0
  8. package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  9. package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  10. package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  11. package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  12. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  13. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  14. package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  15. package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
  16. package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  17. package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  18. package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  19. package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  20. package/.agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
  21. package/.agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
  22. package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  23. package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  24. package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +31 -0
  25. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
  26. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
  27. package/.agent/.shared/ui-ux-pro-max/scripts/core.py +258 -0
  28. package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +1067 -0
  29. package/.agent/.shared/ui-ux-pro-max/scripts/search.py +106 -0
  30. package/.agent/ARCHITECTURE.md +288 -0
  31. package/.agent/agents/ambient-agent.md +57 -0
  32. package/.agent/agents/debugger.md +55 -0
  33. package/.agent/agents/email-assistant.md +49 -0
  34. package/.agent/agents/file-manager.md +42 -0
  35. package/.agent/agents/python-developer.md +60 -0
  36. package/.agent/agents/scheduler.md +59 -0
  37. package/.agent/agents/web-developer.md +45 -0
  38. package/.agent/data/default.json +29 -0
  39. package/.agent/data/plugins-state.json +255 -0
  40. package/.agent/mcp_config.json +4 -0
  41. package/.agent/mcp_config_updated.json +12 -0
  42. package/.agent/plugins.json +5 -0
  43. package/.agent/rules/GEMINI.md +273 -0
  44. package/.agent/rules/allow-rule.md +77 -0
  45. package/.agent/rules/log-rule.md +83 -0
  46. package/.agent/rules/security-rule.md +93 -0
  47. package/.agent/scripts/auto_preview.py +148 -0
  48. package/.agent/scripts/checklist.py +217 -0
  49. package/.agent/scripts/session_manager.py +120 -0
  50. package/.agent/scripts/verify_all.py +327 -0
  51. package/.agent/skills/api-patterns/SKILL.md +81 -0
  52. package/.agent/skills/api-patterns/api-style.md +42 -0
  53. package/.agent/skills/api-patterns/auth.md +24 -0
  54. package/.agent/skills/api-patterns/documentation.md +26 -0
  55. package/.agent/skills/api-patterns/graphql.md +41 -0
  56. package/.agent/skills/api-patterns/rate-limiting.md +31 -0
  57. package/.agent/skills/api-patterns/response.md +37 -0
  58. package/.agent/skills/api-patterns/rest.md +40 -0
  59. package/.agent/skills/api-patterns/scripts/api_validator.py +211 -0
  60. package/.agent/skills/api-patterns/security-testing.md +122 -0
  61. package/.agent/skills/api-patterns/trpc.md +41 -0
  62. package/.agent/skills/api-patterns/versioning.md +22 -0
  63. package/.agent/skills/app-builder/SKILL.md +75 -0
  64. package/.agent/skills/app-builder/agent-coordination.md +71 -0
  65. package/.agent/skills/app-builder/feature-building.md +53 -0
  66. package/.agent/skills/app-builder/project-detection.md +34 -0
  67. package/.agent/skills/app-builder/scaffolding.md +118 -0
  68. package/.agent/skills/app-builder/tech-stack.md +40 -0
  69. package/.agent/skills/app-builder/templates/SKILL.md +39 -0
  70. package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
  71. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
  72. package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
  73. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
  74. package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
  75. package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
  76. package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
  77. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
  78. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
  79. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
  80. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
  81. package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
  82. package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
  83. package/.agent/skills/architecture/SKILL.md +55 -0
  84. package/.agent/skills/architecture/context-discovery.md +43 -0
  85. package/.agent/skills/architecture/examples.md +94 -0
  86. package/.agent/skills/architecture/pattern-selection.md +68 -0
  87. package/.agent/skills/architecture/patterns-reference.md +50 -0
  88. package/.agent/skills/architecture/trade-off-analysis.md +77 -0
  89. package/.agent/skills/clean-code/SKILL.md +201 -0
  90. package/.agent/skills/doc.md +177 -0
  91. package/.agent/skills/frontend-design/SKILL.md +418 -0
  92. package/.agent/skills/frontend-design/animation-guide.md +331 -0
  93. package/.agent/skills/frontend-design/color-system.md +311 -0
  94. package/.agent/skills/frontend-design/decision-trees.md +418 -0
  95. package/.agent/skills/frontend-design/motion-graphics.md +306 -0
  96. package/.agent/skills/frontend-design/scripts/accessibility_checker.py +183 -0
  97. package/.agent/skills/frontend-design/scripts/ux_audit.py +722 -0
  98. package/.agent/skills/frontend-design/typography-system.md +345 -0
  99. package/.agent/skills/frontend-design/ux-psychology.md +1116 -0
  100. package/.agent/skills/frontend-design/visual-effects.md +383 -0
  101. package/.agent/skills/i18n-localization/SKILL.md +154 -0
  102. package/.agent/skills/i18n-localization/scripts/i18n_checker.py +241 -0
  103. package/.agent/skills/mcp-builder/SKILL.md +176 -0
  104. package/.agent/skills/web-design-guidelines/SKILL.md +57 -0
  105. package/.agent/workflows/brainstorm.md +113 -0
  106. package/.agent/workflows/create.md +59 -0
  107. package/.agent/workflows/debug.md +103 -0
  108. package/.agent/workflows/deploy.md +176 -0
  109. package/.agent/workflows/enhance.md +63 -0
  110. package/.agent/workflows/orchestrate.md +237 -0
  111. package/.agent/workflows/plan.md +89 -0
  112. package/.agent/workflows/preview.md +81 -0
  113. package/.agent/workflows/simple-test.md +42 -0
  114. package/.agent/workflows/status.md +86 -0
  115. package/.agent/workflows/structured-orchestrate.md +180 -0
  116. package/.agent/workflows/test.md +144 -0
  117. package/.agent/workflows/ui-ux-pro-max.md +296 -0
  118. package/.claude/settings.local.json +11 -1
  119. package/.editorconfig +56 -0
  120. package/.husky/pre-commit +4 -0
  121. package/.lintstagedrc +7 -0
  122. package/.prettierignore +29 -0
  123. package/.prettierrc +11 -0
  124. package/CLAUDE.md +2 -0
  125. package/README.md +64 -55
  126. package/SPEC.md +102 -61
  127. package/cli/bin/foliko.js +11 -11
  128. package/cli/src/commands/chat.js +143 -141
  129. package/cli/src/commands/list.js +93 -90
  130. package/cli/src/index.js +75 -75
  131. package/cli/src/ui/chat-ui.js +201 -199
  132. package/cli/src/utils/ansi.js +40 -40
  133. package/cli/src/utils/markdown.js +292 -296
  134. package/docker-compose.yml +1 -1
  135. package/docs/ai-sdk-optimization.md +655 -643
  136. package/docs/features.md +80 -80
  137. package/docs/quick-reference.md +49 -46
  138. package/docs/user-manual.md +411 -380
  139. package/examples/ambient-example.js +194 -196
  140. package/examples/basic.js +50 -45
  141. package/examples/bootstrap.js +121 -112
  142. package/examples/mcp-example.js +19 -16
  143. package/examples/skill-example.js +20 -20
  144. package/examples/test-chat.js +137 -135
  145. package/examples/test-mcp.js +85 -79
  146. package/examples/test-reload.js +59 -61
  147. package/examples/test-telegram.js +50 -50
  148. package/examples/test-tg-bot.js +45 -42
  149. package/examples/test-tg-simple.js +47 -46
  150. package/examples/test-tg.js +62 -62
  151. package/examples/test-think.js +43 -37
  152. package/examples/test-web-plugin.js +103 -98
  153. package/examples/test-weixin-feishu.js +103 -100
  154. package/examples/workflow.js +158 -158
  155. package/package.json +37 -3
  156. package/plugins/ai-plugin.js +102 -100
  157. package/plugins/ambient-agent/EventWatcher.js +113 -0
  158. package/plugins/ambient-agent/ExplorerLoop.js +640 -0
  159. package/plugins/ambient-agent/GoalManager.js +197 -0
  160. package/plugins/ambient-agent/Reflector.js +95 -0
  161. package/plugins/ambient-agent/StateStore.js +90 -0
  162. package/plugins/ambient-agent/constants.js +101 -0
  163. package/plugins/ambient-agent/index.js +579 -0
  164. package/plugins/audit-plugin.js +187 -187
  165. package/plugins/default-plugins.js +662 -649
  166. package/plugins/email/constants.js +64 -0
  167. package/plugins/email/handlers.js +461 -0
  168. package/plugins/email/index.js +278 -0
  169. package/plugins/email/monitor.js +269 -0
  170. package/plugins/email/parser.js +138 -0
  171. package/plugins/email/reply.js +151 -0
  172. package/plugins/email/utils.js +124 -0
  173. package/plugins/feishu-plugin.js +481 -477
  174. package/plugins/file-system-plugin.js +826 -476
  175. package/plugins/install-plugin.js +199 -197
  176. package/plugins/python-executor-plugin.js +367 -365
  177. package/plugins/python-plugin-loader.js +481 -479
  178. package/plugins/rules-plugin.js +294 -292
  179. package/plugins/scheduler-plugin.js +691 -689
  180. package/plugins/session-plugin.js +369 -367
  181. package/plugins/shell-executor-plugin.js +197 -197
  182. package/plugins/storage-plugin.js +240 -238
  183. package/plugins/subagent-plugin.js +845 -785
  184. package/plugins/telegram-plugin.js +482 -475
  185. package/plugins/think-plugin.js +345 -343
  186. package/plugins/tools-plugin.js +196 -194
  187. package/plugins/web-plugin.js +606 -604
  188. package/plugins/weixin-plugin.js +545 -538
  189. package/reports/system-health-report-20260401.md +79 -0
  190. package/skills/ambient-agent/SKILL.md +49 -39
  191. package/skills/foliko-dev/AGENTS.md +64 -61
  192. package/skills/foliko-dev/SKILL.md +125 -119
  193. package/skills/mcp-usage/SKILL.md +19 -17
  194. package/skills/python-plugin-dev/SKILL.md +16 -15
  195. package/skills/skill-guide/SKILL.md +12 -12
  196. package/skills/subagent-guide/SKILL.md +237 -0
  197. package/skills/workflow-guide/SKILL.md +90 -45
  198. package/skills/workflow-troubleshooting/DEBUGGING.md +36 -21
  199. package/skills/workflow-troubleshooting/SKILL.md +156 -79
  200. package/src/capabilities/index.js +11 -11
  201. package/src/capabilities/skill-manager.js +609 -595
  202. package/src/capabilities/workflow-engine.js +1109 -1195
  203. package/src/core/agent-chat.js +882 -735
  204. package/src/core/agent.js +892 -688
  205. package/src/core/framework.js +465 -431
  206. package/src/core/index.js +19 -19
  207. package/src/core/plugin-base.js +219 -219
  208. package/src/core/plugin-manager.js +863 -767
  209. package/src/core/provider.js +114 -111
  210. package/src/core/sub-agent-config.js +264 -0
  211. package/src/core/system-prompt-builder.js +120 -0
  212. package/src/core/tool-registry.js +517 -134
  213. package/src/core/tool-router.js +297 -216
  214. package/src/executors/executor-base.js +12 -12
  215. package/src/executors/mcp-executor.js +741 -729
  216. package/src/index.js +25 -37
  217. package/src/utils/circuit-breaker.js +301 -0
  218. package/src/utils/error-boundary.js +363 -0
  219. package/src/utils/error.js +374 -0
  220. package/src/utils/event-emitter.js +97 -97
  221. package/src/utils/id.js +133 -0
  222. package/src/utils/index.js +217 -3
  223. package/src/utils/logger.js +181 -0
  224. package/src/utils/plugin-helpers.js +90 -0
  225. package/src/utils/retry.js +122 -0
  226. package/src/utils/sandbox.js +292 -0
  227. package/test/tool-registry-validation.test.js +218 -0
  228. package/test_report.md +70 -0
  229. package/website/docs/api.html +169 -107
  230. package/website/docs/configuration.html +296 -144
  231. package/website/docs/plugin-development.html +154 -85
  232. package/website/docs/project-structure.html +110 -109
  233. package/website/docs/skill-development.html +117 -61
  234. package/website/index.html +209 -205
  235. package/website/script.js +136 -133
  236. package/website/styles.css +1 -1
  237. package/plugins/ambient-agent-plugin.js +0 -1565
  238. package/plugins/email.js +0 -1142
@@ -1,1565 +0,0 @@
1
- /**
2
- * Ambient Agent 插件
3
- * 持续后台运行的智能代理,监控事件并主动执行操作
4
- */
5
-
6
- const { Plugin } = require('../src/core/plugin-base')
7
- const { StepExecutor } = require('../src/capabilities/workflow-engine')
8
- const { Agent } = require('../src/core/agent')
9
- const { z } = require('zod')
10
- const fs = require('fs')
11
- const path = require('path')
12
-
13
- // 目标生命周期状态
14
- const GoalState = {
15
- PENDING: 'pending', // 待激活
16
- ACTIVE: 'active', // 执行中
17
- COMPLETED: 'completed', // 已完成
18
- FAILED: 'failed' // 已失败
19
- }
20
-
21
- // 生成唯一ID
22
- function generateId() {
23
- if (require('crypto').randomUUID) {
24
- return require('crypto').randomUUID()
25
- }
26
- return `goal_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
27
- }
28
-
29
- // ============================================================================
30
- // StateStore - 持久化目标和记忆到 .agent/data/ambient/*.json
31
- // ============================================================================
32
- class StateStore {
33
- constructor(persistencePath) {
34
- this._persistencePath = persistencePath
35
- this._ensureDir()
36
- }
37
-
38
- _ensureDir() {
39
- if (!fs.existsSync(this._persistencePath)) {
40
- fs.mkdirSync(this._persistencePath, { recursive: true })
41
- }
42
- }
43
-
44
- _getGoalsPath() {
45
- return path.join(this._persistencePath, 'goals.json')
46
- }
47
-
48
- _getMemoriesPath() {
49
- return path.join(this._persistencePath, 'memories.json')
50
- }
51
-
52
- saveGoals(goals) {
53
- try {
54
- fs.writeFileSync(this._getGoalsPath(), JSON.stringify(goals, null, 2))
55
- } catch (err) {
56
- console.error('[Ambient] 保存目标失败:', err.message)
57
- }
58
- }
59
-
60
- loadGoals() {
61
- try {
62
- const filePath = this._getGoalsPath()
63
- if (fs.existsSync(filePath)) {
64
- const data = fs.readFileSync(filePath, 'utf-8')
65
- return JSON.parse(data)
66
- }
67
- } catch (err) {
68
- console.error('[Ambient] 加载目标失败:', err.message)
69
- }
70
- return []
71
- }
72
-
73
- saveMemories(memories) {
74
- try {
75
- fs.writeFileSync(this._getMemoriesPath(), JSON.stringify(memories, null, 2))
76
- } catch (err) {
77
- console.error('[Ambient] 保存记忆失败:', err.message)
78
- }
79
- }
80
-
81
- loadMemories() {
82
- try {
83
- const filePath = this._getMemoriesPath()
84
- if (fs.existsSync(filePath)) {
85
- const data = fs.readFileSync(filePath, 'utf-8')
86
- return JSON.parse(data)
87
- }
88
- } catch (err) {
89
- console.error('[Ambient] 加载记忆失败:', err.message)
90
- }
91
- return []
92
- }
93
- }
94
-
95
- // ============================================================================
96
- // GoalManager - 管理目标及其生命周期状态
97
- // ============================================================================
98
- class GoalManager {
99
- constructor(stateStore) {
100
- this._goals = new Map()
101
- this._stateStore = stateStore
102
- this._loadGoals()
103
- }
104
-
105
- _loadGoals() {
106
- const savedGoals = this._stateStore.loadGoals()
107
- for (const goal of savedGoals) {
108
- this._goals.set(goal.id, goal)
109
- }
110
- }
111
-
112
- _persist() {
113
- const goalsArray = Array.from(this._goals.values())
114
- this._stateStore.saveGoals(goalsArray)
115
- }
116
-
117
- createGoal(goalData) {
118
- const actions = goalData.actions || []
119
- const goal = {
120
- id: generateId(),
121
- title: goalData.title || '未命名目标',
122
- description: goalData.description || '',
123
- priority: goalData.priority || 5,
124
- state: GoalState.PENDING,
125
- actions: actions,
126
- _originalActions: actions.slice(), // 保存原始 actions,用于事件驱动目标重置
127
- conditions: goalData.conditions || {},
128
- createdAt: new Date(),
129
- updatedAt: new Date(),
130
- activatedAt: null,
131
- completedAt: null,
132
- failedAt: null,
133
- attempts: 0,
134
- maxAttempts: goalData.maxAttempts || 10,
135
- consecutiveSameActions: 0,
136
- lastActionId: null,
137
- eventsReceived: []
138
- }
139
- this._goals.set(goal.id, goal)
140
- this._persist()
141
- return goal
142
- }
143
-
144
- getGoal(id) {
145
- return this._goals.get(id)
146
- }
147
-
148
- getAllGoals() {
149
- return Array.from(this._goals.values())
150
- }
151
-
152
- getActiveGoals() {
153
- return Array.from(this._goals.values()).filter(g => g.state === GoalState.ACTIVE)
154
- }
155
-
156
- getPendingGoals() {
157
- return Array.from(this._goals.values()).filter(g => g.state === GoalState.PENDING)
158
- }
159
-
160
- updateGoal(id, updates) {
161
- const goal = this._goals.get(id)
162
- if (!goal) return null
163
- Object.assign(goal, updates, { updatedAt: new Date() })
164
- this._persist()
165
- return goal
166
- }
167
-
168
- activateGoal(id) {
169
- const goal = this._goals.get(id)
170
- if (!goal || goal.state !== GoalState.PENDING) return null
171
- goal.state = GoalState.ACTIVE
172
- goal.activatedAt = new Date()
173
- goal.updatedAt = new Date()
174
- this._persist()
175
- return goal
176
- }
177
-
178
- completeGoal(id) {
179
- const goal = this._goals.get(id)
180
- if (!goal) return null
181
- goal.state = GoalState.COMPLETED
182
- goal.completedAt = new Date()
183
- goal.updatedAt = new Date()
184
- this._persist()
185
- return goal
186
- }
187
-
188
- failGoal(id, reason) {
189
- const goal = this._goals.get(id)
190
- if (!goal) return null
191
- goal.state = GoalState.FAILED
192
- goal.failedAt = new Date()
193
- goal.failureReason = reason
194
- goal.updatedAt = new Date()
195
- this._persist()
196
- return goal
197
- }
198
-
199
- deleteGoal(id) {
200
- const deleted = this._goals.delete(id)
201
- if (deleted) this._persist()
202
- return deleted
203
- }
204
-
205
- addEventToGoal(goalId, event) {
206
- const goal = this._goals.get(goalId)
207
- if (!goal) return
208
-
209
- // 通用去重:如果最近 2 秒内已有相同类型的事件,跳过
210
- const now = Date.now()
211
- const recentSameEvent = goal.eventsReceived.find(e =>
212
- e.event === event.type && (now - new Date(e.timestamp).getTime()) < 2000
213
- )
214
- if (recentSameEvent) {
215
- console.log(`[Ambient] 跳过重复事件: ${event.type} (2秒内不重复添加)`)
216
- return
217
- }
218
-
219
- // event 格式: { type: 'email:received', email: {...}, timestamp: ... }
220
- // 需要提取 type 和 data(email 对象)
221
- goal.eventsReceived.push({
222
- event: event.type,
223
- data: event.data || event.email || event,
224
- timestamp: new Date()
225
- })
226
- this._persist()
227
- }
228
- }
229
-
230
- // ============================================================================
231
- // EventWatcher - 订阅框架事件,筛选相关事件
232
- // ============================================================================
233
- class EventWatcher {
234
- constructor(goalManager, framework) {
235
- this._goalManager = goalManager
236
- this._framework = framework
237
- this._handlers = []
238
- this._relevantEvents = new Set([
239
- 'tool:result', // 工具执行结果
240
- 'scheduler:reminder', // 定时提醒
241
- 'agent:message', // 代理消息
242
- 'think:thought_completed', // 思考完成
243
- 'email:received', // 收到邮件
244
- 'webhook:received' // Webhook接收
245
- ])
246
- }
247
-
248
- start() {
249
- const events = [
250
- ['tool:result', (data) => this._handleEvent('tool:result', data)],
251
- ['scheduler:reminder', (data) => this._handleEvent('scheduler:reminder', data)],
252
- ['agent:message', (data) => this._handleEvent('agent:message', data)],
253
- ['think:thought_completed', (data) => this._handleEvent('think:thought_completed', data)],
254
- ['scheduler:task_completed', (data) => this._handleEvent('scheduler:task_completed', data)],
255
- ['scheduler:task_failed', (data) => this._handleEvent('scheduler:task_failed', data)],
256
- ['email:received', (data) => this._handleEvent('email:received', data)],
257
- ['webhook:received', (data) => this._handleEvent('webhook:received', data)]
258
- ]
259
-
260
- for (const [event, handler] of events) {
261
- this._framework.on(event, handler)
262
- this._handlers.push({ event, handler })
263
- }
264
- }
265
-
266
- stop() {
267
- for (const { event, handler } of this._handlers) {
268
- this._framework.off(event, handler)
269
- }
270
- this._handlers = []
271
- }
272
-
273
- _handleEvent(type, data) {
274
- const activeGoals = this._goalManager.getActiveGoals()
275
- console.log(`[Ambient] _handleEvent: type=${type}, activeGoals=${activeGoals.length}`)
276
- for (const goal of activeGoals) {
277
- // 检查目标条件是否匹配此事件
278
- const isRelevant = this._isRelevantToGoal(goal, type, data)
279
- console.log(`[Ambient] goal=${goal.id}, isRelevant=${isRelevant}, conditions=${JSON.stringify(goal.conditions)}`)
280
- if (isRelevant) {
281
- // 将 data 展平到事件对象中,方便通过 {{_event.xxx}} 访问
282
- this._goalManager.addEventToGoal(goal.id, { type, ...data })
283
- console.log(`[Ambient] Event added to goal ${goal.id}`)
284
- }
285
- }
286
-
287
- // 检查是否有 pending 目标需要激活
288
- const pendingGoals = this._goalManager.getPendingGoals()
289
- for (const goal of pendingGoals) {
290
- if (this._isRelevantToGoal(goal, type, data)) {
291
- // 激活目标
292
- this._goalManager.activateGoal(goal.id)
293
- // 添加事件
294
- this._goalManager.addEventToGoal(goal.id, { type, ...data })
295
- console.log(`[Ambient] 事件触发激活目标: ${goal.id} (事件: ${type})`)
296
- }
297
- }
298
- }
299
-
300
- _isRelevantToGoal(goal, eventType, data) {
301
- // 检查条件中是否有明确的事件类型
302
- if (goal.conditions && goal.conditions.events) {
303
- const allowedEvents = Array.isArray(goal.conditions.events)
304
- ? goal.conditions.events
305
- : [goal.conditions.events]
306
- if (!allowedEvents.includes(eventType)) {
307
- return false
308
- }
309
- }
310
- // 检查工具名称过滤器
311
- if (goal.conditions && goal.conditions.toolNames) {
312
- const toolNames = Array.isArray(goal.conditions.toolNames)
313
- ? goal.conditions.toolNames
314
- : [goal.conditions.toolNames]
315
- if (data && data.toolName && !toolNames.includes(data.toolName)) {
316
- return false
317
- }
318
- }
319
- return true
320
- }
321
- }
322
-
323
- // ============================================================================
324
- // Reflector - 评估操作结果,更新目标状态
325
- // ============================================================================
326
- class Reflector {
327
- constructor(goalManager) {
328
- this._goalManager = goalManager
329
- }
330
-
331
- evaluateOutcome(goal, actionResult) {
332
- if (!goal) return null
333
-
334
- // 检查是否是事件驱动目标
335
- const isEventDriven = goal.conditions?.events && goal.conditions.events.length > 0
336
-
337
- // 检查错误
338
- if (actionResult && actionResult.error) {
339
- // 增加尝试次数但不立即失败
340
- goal.attempts++
341
- // 事件驱动目标:错误不导致失败或完成
342
- if (isEventDriven) {
343
- return { shouldContinue: true, goalComplete: false }
344
- }
345
- return {
346
- shouldContinue: goal.attempts < goal.maxAttempts,
347
- actionTaken: false
348
- }
349
- }
350
-
351
- // 检查是否成功完成
352
- if (actionResult && actionResult.success === true) {
353
- goal.attempts++
354
-
355
- // 事件驱动目标:永远不会完成,持续等待下一事件
356
- if (isEventDriven) {
357
- return { shouldContinue: true, goalComplete: false }
358
- }
359
-
360
- // 检查目标是否完成
361
- if (goal.actions.length === 0 || goal.attempts >= goal.maxAttempts) {
362
- return { shouldContinue: false, goalComplete: true }
363
- }
364
-
365
- return { shouldContinue: true, actionTaken: true }
366
- }
367
-
368
- // 工具执行无错误 - 视为成功
369
- goal.attempts++
370
-
371
- // 事件驱动目标:永远不会完成
372
- if (isEventDriven) {
373
- return { shouldContinue: true, goalComplete: false }
374
- }
375
-
376
- // 检查目标是否完成(没有更多操作)
377
- if (goal.actions.length === 0 || goal.attempts >= goal.maxAttempts) {
378
- return { shouldContinue: false, goalComplete: true }
379
- }
380
-
381
- return { shouldContinue: true, actionTaken: true }
382
- }
383
-
384
- checkLoopDetection(goal, actionId) {
385
- // 如果同一操作连续重复3次,则目标失败
386
- if (goal.lastActionId === actionId) {
387
- goal.consecutiveSameActions++
388
- if (goal.consecutiveSameActions >= 3) {
389
- this._goalManager.failGoal(goal.id, '检测到循环:同一操作连续重复3次')
390
- return true
391
- }
392
- } else {
393
- goal.consecutiveSameActions = 1
394
- goal.lastActionId = actionId
395
- }
396
- return false
397
- }
398
- }
399
-
400
- // ============================================================================
401
- // ExplorerLoop - 主自主循环,决定并执行操作
402
- // ============================================================================
403
- class ExplorerLoop {
404
- constructor(goalManager, reflector, framework, config) {
405
- this._goalManager = goalManager
406
- this._reflector = reflector
407
- this._framework = framework
408
- this._config = config
409
- this._running = false
410
- this._timer = null
411
- this._lastActionTime = 0
412
- this._tickCount = 0
413
- this._recentActivities = []
414
- this._stepExecutor = new StepExecutor(framework)
415
- this._ambientAgent = null
416
- this._initAmbientAgent()
417
- }
418
-
419
- /**
420
- * 初始化 Ambient 专用子 Agent
421
- */
422
- _initAmbientAgent() {
423
- const aiPlugin = this._framework.pluginManager?.get('ai')
424
- const llmConfig = aiPlugin ? aiPlugin.getConfig() : {}
425
-
426
- this._ambientAgent = new Agent(this._framework, {
427
- name: 'ambient-worker',
428
- systemPrompt: `你是 ambient-worker,一个专门执行后台任务的子 agent。
429
-
430
- 你的职责:
431
- 1. 执行 LLM 调用的任务(如生成回复、发送消息)
432
- 2. 不主动思考,只执行给定任务
433
- 3. 快速响应,不等待用户交互
434
-
435
- 当收到任务时,直接执行并返回结果。`,
436
- model: llmConfig.model,
437
- provider: llmConfig.provider,
438
- apiKey: llmConfig.apiKey,
439
- baseURL: llmConfig.baseURL
440
- })
441
-
442
- // 注册到主 agent(如果主 agent 已存在)
443
- if (this._framework._mainAgent) {
444
- this._registerAmbientWorker(this._framework._mainAgent)
445
- } else {
446
- // 等待主 agent 创建
447
- this._framework.once('agent:created', (agent) => {
448
- if (this._framework._mainAgent && agent === this._framework._mainAgent) {
449
- this._registerAmbientWorker(agent)
450
- }
451
- })
452
- }
453
- }
454
-
455
- /**
456
- * 注册 ambient-worker 到主 agent
457
- */
458
- _registerAmbientWorker(agent) {
459
- if (!this._ambientAgent) return
460
- agent.registerSubAgent(
461
- 'ambient-worker',
462
- this._ambientAgent,
463
- '后台任务执行器',
464
- '执行需要 AI 能力的后台任务'
465
- )
466
- console.log('[Ambient] ambient-worker subagent registered')
467
- }
468
-
469
- start() {
470
- if (this._running) return
471
- this._running = true
472
- this._scheduleNext()
473
- }
474
-
475
- stop() {
476
- this._running = false
477
- if (this._timer) {
478
- clearTimeout(this._timer)
479
- this._timer = null
480
- }
481
- }
482
-
483
- pause() {
484
- this._running = false
485
- if (this._timer) {
486
- clearTimeout(this._timer)
487
- this._timer = null
488
- }
489
- }
490
-
491
- resume() {
492
- if (!this._running) {
493
- this._running = true
494
- this._scheduleNext()
495
- }
496
- }
497
-
498
- isRunning() {
499
- return this._running
500
- }
501
-
502
- getStatus() {
503
- return {
504
- running: this._running,
505
- tickCount: this._tickCount,
506
- lastTick: this._lastActionTime ? new Date(this._lastActionTime) : null,
507
- recentActivities: this._recentActivities.slice(-10),
508
- activeGoals: this._goalManager.getActiveGoals().length,
509
- pendingGoals: this._goalManager.getPendingGoals().length
510
- }
511
- }
512
-
513
- _scheduleNext() {
514
- if (!this._running) return
515
- this._timer = setTimeout(() => this._tick(), this._config.tickInterval)
516
- }
517
-
518
- async _tick() {
519
- if (!this._running) return
520
-
521
- // 如果处于嵌套执行上下文中,跳过此tick
522
- try {
523
- if (this._framework.getExecutionContext) {
524
- const ctx = this._framework.getExecutionContext()
525
- if (ctx && ctx.id) {
526
- // 跳过此tick,重新调度
527
- this._scheduleNext()
528
- return
529
- }
530
- }
531
- } catch (e) {
532
- // getExecutionContext可能不存在,继续执行
533
- }
534
-
535
- this._tickCount++
536
-
537
-
538
- try {
539
- await this._processGoals()
540
- } catch (err) {
541
- console.error('[Ambient] Tick错误:', err.message)
542
- this._addActivity('error', { message: err.message })
543
- }
544
- this._lastActionTime = Date.now()
545
- // 调度下一次tick
546
- this._scheduleNext()
547
- }
548
-
549
- async _processGoals() {
550
- const activeGoals = this._goalManager.getActiveGoals()
551
-
552
- for (const goal of activeGoals) {
553
- // 检查冷却时间
554
- if (Date.now() - this._lastActionTime < this._config.cooldownPeriod) {
555
- continue
556
- }
557
-
558
- // 检查目标是否有未处理的事件
559
- const hasNewEvents = goal.eventsReceived && goal.eventsReceived.length > 0
560
-
561
- // 检查是否是事件驱动目标
562
- const isEventDriven = goal.conditions?.events && goal.conditions.events.length > 0
563
-
564
- // 事件驱动目标:只有在新事件时才执行 actions
565
- if (isEventDriven && !hasNewEvents) {
566
- continue
567
- }
568
-
569
- // 获取下一个操作
570
- if (goal.actions && goal.actions.length > 0) {
571
- // 如果有多个 action,按顺序执行所有 action
572
- if (goal.actions.length > 1) {
573
- const eventData = hasNewEvents ? goal.eventsReceived[0] : null
574
- const results = await this._executeAllActions(goal.actions, eventData)
575
-
576
- // 最后一个结果用于评估
577
- const lastResult = results.length > 0 ? results[results.length - 1].result : null
578
-
579
- // 评估结果
580
- const outcome = this._reflector.evaluateOutcome(goal, lastResult)
581
-
582
- // 检查是否是事件驱动目标
583
- const isEventDriven = goal.conditions?.events && goal.conditions.events.length > 0
584
-
585
- if (outcome.goalComplete && !isEventDriven) {
586
- // 非事件驱动目标可以完成
587
- this._goalManager.completeGoal(goal.id)
588
- this._addActivity('goal_completed', { goalId: goal.id, attempts: goal.attempts })
589
- this._notifyUser('目标完成', `目标 "${goal.title}" 已完成(尝试次数:${goal.attempts})`, 'success')
590
- } else if (!outcome.shouldContinue && !isEventDriven) {
591
- // 非事件驱动目标可以失败
592
- this._goalManager.failGoal(goal.id, '达到最大尝试次数')
593
- this._addActivity('goal_failed', { goalId: goal.id, reason: '达到最大尝试次数' })
594
- this._notifyUser('目标失败', `目标 "${goal.title}" 失败:达到最大尝试次数`, 'error')
595
- } else {
596
- // 事件驱动目标:不论结果如何,都重置并继续等待下一事件
597
- this._addActivity('actions_completed', { goalId: goal.id, actionCount: results.length })
598
- }
599
-
600
- // 执行操作后清除已处理的事件,并重置 actions 以处理下一事件
601
- if (hasNewEvents) {
602
- goal.eventsReceived = []
603
- // 重置 actions 为原始 actions,以便处理下一事件
604
- if (goal._originalActions) {
605
- goal.actions = goal._originalActions.slice()
606
- }
607
- this._goalManager.updateGoal(goal.id, { eventsReceived: [], actions: goal.actions })
608
- }
609
- continue
610
- }
611
-
612
- // 单个 action,使用原有逻辑
613
- const action = goal.actions[0]
614
-
615
- // 循环检测(仅用于非事件驱动的操作)
616
- if (!hasNewEvents && this._reflector.checkLoopDetection(goal, action.id)) {
617
- this._addActivity('goal_failed', { goalId: goal.id, reason: '检测到循环' })
618
- // 通知用户目标失败
619
- this._notifyUser('目标失败', `目标 "${goal.title}" 失败:检测到循环(同一操作连续重复)`, 'error')
620
- continue
621
- }
622
-
623
- // 执行操作
624
- const result = await this._executeAction(action, hasNewEvents ? goal.eventsReceived[0] : null)
625
-
626
- // 评估结果
627
- const outcome = this._reflector.evaluateOutcome(goal, result)
628
-
629
- if (outcome.goalComplete) {
630
- this._goalManager.completeGoal(goal.id)
631
- this._addActivity('goal_completed', { goalId: goal.id, attempts: goal.attempts })
632
- // 通知用户目标完成
633
- this._notifyUser('目标完成', `目标 "${goal.title}" 已完成(尝试次数:${goal.attempts})`, 'success')
634
- } else if (!outcome.shouldContinue) {
635
- this._goalManager.failGoal(goal.id, '达到最大尝试次数')
636
- this._addActivity('goal_failed', { goalId: goal.id, reason: '达到最大尝试次数' })
637
- // 通知用户目标失败
638
- this._notifyUser('目标失败', `目标 "${goal.title}" 失败:达到最大尝试次数`, 'error')
639
- } else if (outcome.actionTaken) {
640
- // 从队列中移除已完成的操作
641
- // 注意:对于事件驱动目标,如果 hasNewEvents 为 true,不移除 action 而是在下面重置
642
- if (!hasNewEvents) {
643
- goal.actions.shift()
644
- }
645
- this._addActivity('action_executed', { goalId: goal.id, action: action.id, hasEvents: hasNewEvents })
646
- }
647
-
648
- // 执行操作后清除已处理的事件,并重置 actions 以处理下一事件
649
- if (hasNewEvents) {
650
- goal.eventsReceived = []
651
- // 重置 actions 为原始 actions,以便处理下一事件
652
- if (goal._originalActions) {
653
- goal.actions = goal._originalActions.slice()
654
- }
655
- this._goalManager.updateGoal(goal.id, { eventsReceived: [], actions: goal.actions })
656
- }
657
- }
658
- }
659
-
660
- // 激活满足条件的待处理目标
661
- const pendingGoals = this._goalManager.getPendingGoals()
662
- for (const goal of pendingGoals) {
663
- // 自动激活没有条件的目标
664
- // 有条件的目标会在事件触发时被 EventWatcher 自动激活
665
- if (!goal.conditions || Object.keys(goal.conditions).length === 0) {
666
- this._goalManager.activateGoal(goal.id)
667
- this._addActivity('goal_activated', { goalId: goal.id })
668
- } else {
669
- // 有条件的目标,立即激活以便开始监听事件
670
- this._goalManager.activateGoal(goal.id)
671
- this._addActivity('goal_activated', { goalId: goal.id, reason: '事件监听目标已激活' })
672
- }
673
- }
674
- }
675
-
676
- /**
677
- * 执行单个 action
678
- * @param {Object} action - action 配置
679
- * @param {Object} eventData - 事件数据
680
- * @param {Object} context - 执行上下文(包含 stepOutputs 等)
681
- * @returns {Promise<Object>} 执行结果
682
- */
683
- async _executeAction(action, eventData = null, context = null) {
684
- if (!this._framework) {
685
- return { success: false, error: '框架不可用' }
686
- }
687
-
688
- try {
689
- // 如果没有提供 context,创建一个新的
690
- if (!context) {
691
- context = {
692
- input: {},
693
- variables: {
694
- _event: eventData?.data || eventData || null,
695
- _eventRaw: eventData || null,
696
- _action: action
697
- },
698
- lastResult: null
699
- }
700
- } else {
701
- // 更新 context 中的 _action
702
- context.variables._action = action
703
- }
704
-
705
- // 将 action 转换为 step 配置
706
- const step = this._actionToStep(action)
707
-
708
- // 解析 step.args 中的变量引用(支持 ${actionId.output} 格式)
709
- if (step.args) {
710
- step.args = this._resolveActionArgs(step.args, context)
711
- }
712
- if (step.input) {
713
- step.input = this._resolveActionArgs(step.input, context)
714
- }
715
-
716
- // message 和 think 类型使用专用子 agent 执行
717
- if (step.type === 'message' || step.type === 'think') {
718
- return await this._executeWithAmbientAgent(step, context)
719
- }
720
-
721
- // 其他类型使用 StepExecutor 直接执行
722
- const result = await this._stepExecutor.executeStep(step, context)
723
- return result
724
- } catch (err) {
725
- return { success: false, error: err.message }
726
- }
727
- }
728
-
729
- /**
730
- * 解析 action 参数中的变量引用
731
- * 支持 ${actionId.output}、${actionId.output.field} 和 ${event.xxx} 格式
732
- * @param {Object} args - 参数对象
733
- * @param {Object} context - 执行上下文
734
- * @returns {Object} 解析后的参数
735
- */
736
- _resolveActionArgs(args, context) {
737
- if (!args || typeof args !== 'object') return args
738
-
739
- const stepOutputs = context.variables._stepOutputs || {}
740
- const eventData = context.variables._event || {}
741
-
742
- const resolved = {}
743
- for (const [key, value] of Object.entries(args)) {
744
- resolved[key] = this._resolveActionValue(value, stepOutputs, eventData)
745
- }
746
- return resolved
747
- }
748
-
749
- /**
750
- * 解析单个值中的 ${actionId.output} 引用和 ${event.xxx} 引用
751
- */
752
- _resolveActionValue(value, stepOutputs, eventData) {
753
- if (typeof value === 'string') {
754
- // 处理 ${actionId.output} 和 ${actionId.output.field} 格式
755
- const result = value.replace(/\$\{([^}]+)\}/g, (match, path) => {
756
- if (path === 'output' || path === 'result') {
757
- // {{result}} 引用上一步结果
758
- return stepOutputs._lastResult ?? match
759
- }
760
- if (path.startsWith('event.')) {
761
- // ${event.xxx} 引用事件数据
762
- let eventPath = path.replace(/^event\./, '')
763
- // 优先在 eventData.data 中查找(因为事件数据通常存储在 data 字段)
764
- if (eventData?.data) {
765
- let val = this._getNestedValue(eventData.data, eventPath)
766
- if (val !== undefined) return val
767
- }
768
- // 再尝试直接在 eventData 中查找
769
- let val = this._getNestedValue(eventData, eventPath)
770
- if (val !== undefined) return val
771
- // 兼容:如果 path 是 event.data.xxx 但 eventData 没有 data,尝试跳过一层
772
- if (eventPath.startsWith('data.')) {
773
- eventPath = eventPath.replace(/^data\./, '')
774
- val = this._getNestedValue(eventData, eventPath)
775
- if (val !== undefined) return val
776
- }
777
- // 特殊回退:如果查找 body 但找不到,尝试 text(邮件数据中用 text)
778
- if (eventPath === 'body' || eventPath === 'text') {
779
- const textVal = this._getNestedValue(eventData?.data, 'text')
780
- if (textVal !== undefined) return textVal
781
- }
782
- return match
783
- }
784
- if (path === 'event') {
785
- // ${event} 引用整个事件数据对象
786
- return eventData ?? match
787
- }
788
- if (path.includes('.')) {
789
- // ${actionId.output.field} 格式
790
- const [actionId, ...fieldParts] = path.split('.')
791
- if (actionId === 'result' || actionId === 'output') {
792
- // {{result.field}} 格式
793
- const val = this._getNestedValue(stepOutputs._lastResult, fieldParts.join('.'))
794
- return val !== undefined ? val : match
795
- }
796
- const actionOutput = stepOutputs[actionId]
797
- if (actionOutput !== undefined) {
798
- const val = this._getNestedValue(actionOutput, fieldParts.join('.'))
799
- return val !== undefined ? val : match
800
- }
801
- } else {
802
- // ${actionId.output} 格式
803
- const actionOutput = stepOutputs[path]
804
- if (actionOutput !== undefined) return actionOutput
805
- }
806
- return match
807
- })
808
- return result
809
- } else if (Array.isArray(value)) {
810
- return value.map(v => this._resolveActionValue(v, stepOutputs, eventData))
811
- } else if (typeof value === 'object' && value !== null) {
812
- const resolved = {}
813
- for (const [k, v] of Object.entries(value)) {
814
- resolved[k] = this._resolveActionValue(v, stepOutputs, eventData)
815
- }
816
- return resolved
817
- }
818
- return value
819
- }
820
-
821
- _getNestedValue(obj, path) {
822
- if (!obj) return undefined
823
- const parts = path.split('.')
824
- let current = obj
825
- for (const part of parts) {
826
- if (current === null || current === undefined) return undefined
827
- current = current[part]
828
- }
829
- return current
830
- }
831
-
832
- /**
833
- * 按顺序执行所有 actions
834
- * @param {Array} actions - action 数组
835
- * @param {Object} eventData - 事件数据
836
- * @returns {Promise<Array>} 所有执行结果
837
- */
838
- async _executeAllActions(actions, eventData = null) {
839
- const results = []
840
- const stepOutputs = {}
841
-
842
- const context = {
843
- input: {},
844
- variables: {
845
- _event: eventData?.data || eventData || null,
846
- _eventRaw: eventData || null,
847
- _stepOutputs: stepOutputs
848
- },
849
- lastResult: null
850
- }
851
-
852
- for (const action of actions) {
853
- // 执行前更新 stepOutputs
854
- context.variables._stepOutputs = stepOutputs
855
-
856
- const result = await this._executeAction(action, eventData, context)
857
-
858
- // 保存结果:使用 action id 作为键
859
- if (action.id) {
860
- stepOutputs[action.id] = result
861
- }
862
- // 同时保存为 _lastResult 供 {{result}} 引用
863
- stepOutputs._lastResult = result
864
- context.lastResult = result
865
-
866
- results.push({ actionId: action.id, result })
867
-
868
- // 如果执行失败,停止执行
869
- if (result && result.success === false) {
870
- break
871
- }
872
- }
873
-
874
- return results
875
- }
876
-
877
- /**
878
- * 使用 ambient 子 agent 执行 AI 相关操作
879
- */
880
- async _executeWithAmbientAgent(step, context) {
881
- if (!this._ambientAgent) {
882
- return { success: false, error: 'Ambient agent 未初始化' }
883
- }
884
-
885
- if (step.type === 'message') {
886
- let content = step.content || ''
887
- content = this._stepExecutor._resolveValue(content, context)
888
-
889
- if (context.variables._event) {
890
- content = `${content}\n\n[事件上下文: ${JSON.stringify(context.variables._event)}]`
891
- }
892
-
893
- try {
894
- const result = await this._ambientAgent.pushMessage(content)
895
- return { success: true, result }
896
- } catch (err) {
897
- return { success: false, error: err.message }
898
- }
899
- }
900
-
901
- if (step.type === 'think') {
902
- const thinkPlugin = this._framework.pluginManager?.get('think')
903
- if (!thinkPlugin) {
904
- return { success: false, error: '思考插件不可用' }
905
- }
906
-
907
- let topic = step.topic || 'Ambient代理反思'
908
- topic = this._stepExecutor._resolveValue(topic, context)
909
-
910
- if (context.variables._event) {
911
- topic = `${topic}\n\n[事件上下文: ${JSON.stringify(context.variables._event)}]`
912
- }
913
-
914
- try {
915
- const result = await thinkPlugin._triggerThinking({
916
- topic,
917
- mode: step.mode || 'reflect',
918
- depth: step.depth || 2
919
- })
920
- return result
921
- } catch (err) {
922
- return { success: false, error: err.message }
923
- }
924
- }
925
-
926
- return { success: false, error: `未知 AI 操作类型: ${step.type}` }
927
- }
928
-
929
- /**
930
- * 将 action 转换为 step 配置
931
- */
932
- _actionToStep(action) {
933
- const step = {
934
- id: action.id || `action_${Date.now()}`,
935
- type: action.type,
936
- name: action.name || action.id
937
- }
938
-
939
- switch (action.type) {
940
- case 'tool':
941
- step.tool = action.name
942
- step.args = action.args || {}
943
- break
944
- case 'message':
945
- step.content = action.content || ''
946
- break
947
- case 'think':
948
- step.topic = action.topic || 'Ambient代理反思'
949
- step.mode = action.mode || 'reflect'
950
- step.depth = action.depth || 2
951
- break
952
- }
953
-
954
- return step
955
- }
956
-
957
- _getActiveAgent() {
958
- if (this._framework._mainAgent) {
959
- return this._framework._mainAgent
960
- }
961
- const agents = this._framework._agents || []
962
- return agents.length > 0 ? agents[agents.length - 1] : null
963
- }
964
-
965
- _addActivity(type, data) {
966
- this._recentActivities.push({
967
- type,
968
- data,
969
- timestamp: new Date()
970
- })
971
- // 只保留最近50条活动记录
972
- if (this._recentActivities.length > 50) {
973
- this._recentActivities = this._recentActivities.slice(-50)
974
- }
975
- }
976
-
977
- /**
978
- * 通知用户(通过事件发送给消息插件)
979
- */
980
- _notifyUser(title, message, level = 'info') {
981
- if (!this._framework) return
982
-
983
- // 获取目标相关的sessionId(如果有)
984
- let sessionId = null
985
- const sessionPlugin = this._framework.pluginManager.get('session')
986
- if (sessionPlugin) {
987
- const sessions = sessionPlugin.listSessions()
988
- if (sessions.length > 0) {
989
- // 取最新的会话
990
- sessions.sort((a, b) => new Date(b.lastActive).getTime() - new Date(a.lastActive).getTime())
991
- sessionId = sessions[0].id
992
- }
993
- }
994
-
995
- // 发送统一的通知事件
996
- this._framework.emit('notification', {
997
- title,
998
- message,
999
- source: 'ambient',
1000
- level, // 'info' | 'warning' | 'success' | 'error'
1001
- sessionId,
1002
- timestamp: new Date()
1003
- })
1004
-
1005
- console.log(`[Ambient:通知] ${title}: ${message}`)
1006
- }
1007
- }
1008
-
1009
- // ============================================================================
1010
- // 主插件类
1011
- // ============================================================================
1012
- class AmbientAgentPlugin extends Plugin {
1013
- constructor(config = {}) {
1014
- super()
1015
- this.name = 'ambient'
1016
- this.version = '1.0.0'
1017
- this.description = `Ambient Agent - 持续后台运行的智能代理,用于主动监控事件并执行操作
1018
-
1019
- ## 支持的事件类型(创建目标时 conditions.events 必须使用这些确切的名称):
1020
- - email:received - 收到新邮件(参数:from, subject, text, messageId)
1021
- - tool:result - 工具执行完成(参数:name, args, result)
1022
- - scheduler:reminder - 定时提醒(参数:taskId, message, time)
1023
- - scheduler:task_completed - 任务完成(参数:taskId, result)
1024
- - scheduler:task_failed - 任务失败(参数:taskId, error)
1025
- - agent:message - 代理消息(参数:content, sessionId)
1026
- - think:thought_completed - 思考完成(参数:mode, topic, thought)
1027
- - webhook:received - Webhook接收(参数:headers, body, query, path)
1028
-
1029
- ## 在 action 参数中引用事件数据:
1030
- 使用 \${event.xxx} 语法,例如:\${event.from}、\${event.subject}、\${event.text}`
1031
- this.priority = 18
1032
- this.system = true
1033
-
1034
- this.config = {
1035
- enabled: config.enabled !== false,
1036
- tickInterval: config.tickInterval || 5000, // tick间隔(毫秒)
1037
- cooldownPeriod: config.cooldownPeriod || 3000, // 冷却时间(毫秒)
1038
- persistencePath: config.persistencePath || '.agent/data/ambient',
1039
- defaultGoals: config.defaultGoals || []
1040
- }
1041
-
1042
- this._framework = null
1043
- this._stateStore = null
1044
- this._goalManager = null
1045
- this._eventWatcher = null
1046
- this._reflector = null
1047
- this._explorerLoop = null
1048
- this._memories = []
1049
- }
1050
-
1051
- install(framework) {
1052
- this._framework = framework
1053
- this._stateStore = new StateStore(this.config.persistencePath)
1054
- this._goalManager = new GoalManager(this._stateStore)
1055
- this._reflector = new Reflector(this._goalManager)
1056
-
1057
- // 加载持久化的记忆
1058
- this._memories = this._stateStore.loadMemories()
1059
-
1060
- return this
1061
- }
1062
-
1063
- start(framework) {
1064
- if (!this.config.enabled) {
1065
- console.log('[Ambient] 插件已禁用,跳过启动')
1066
- return this
1067
- }
1068
-
1069
- // 如果没有现有目标,创建默认目标
1070
- if (this._goalManager.getAllGoals().length === 0 && this.config.defaultGoals.length > 0) {
1071
- for (const goalDef of this.config.defaultGoals) {
1072
- this._goalManager.createGoal(goalDef)
1073
- }
1074
- }
1075
-
1076
- // 启动事件监听器
1077
- this._eventWatcher = new EventWatcher(this._goalManager, this._framework)
1078
- this._eventWatcher.start()
1079
-
1080
- // 动态更新description显示支持的事件及参数
1081
- const eventDescriptions = {
1082
- 'tool:result': '工具执行结果事件 - 参数: name(工具名), args(执行参数), result(执行结果), error(错误信息)',
1083
- 'scheduler:reminder': '定时提醒事件 - 参数: taskId(任务ID), message(提醒消息), time(触发时间)',
1084
- 'scheduler:task_completed': '任务完成事件 - 参数: taskId(任务ID), result(任务结果)',
1085
- 'scheduler:task_failed': '任务失败事件 - 参数: taskId(任务ID), error(错误信息)',
1086
- 'agent:message': '代理消息事件 - 参数: content(消息内容), sessionId(会话ID), agentId(代理ID)',
1087
- 'think:thought_completed': '思考完成事件 - 参数: mode(思考模式), topic(思考主题), thought(思考内容), depth(思考深度)',
1088
- 'email:received': '收到邮件事件 - 参数: from(发件人), to(收件人), subject(主题), text(正文), body(HTML正文), messageId(消息ID), timestamp(时间戳)',
1089
- 'webhook:received': 'Webhook接收事件 - 参数: headers(HTTP头), body(请求体), query(查询参数), path(请求路径)'
1090
- }
1091
-
1092
- const events = Array.from(this._eventWatcher._relevantEvents)
1093
- const eventList = events.map(e => {
1094
- const desc = eventDescriptions[e] || e
1095
- return ` - ${desc}`
1096
- }).join('\n')
1097
-
1098
- this.description = `Ambient Agent - 持续后台运行的智能代理,用于主动监控和执行操作
1099
- 支持的事件及参数:
1100
- ${eventList}
1101
-
1102
- 使用 \${event.xxx} 在 action 参数中引用事件数据`
1103
-
1104
- // 启动探索循环
1105
- this._explorerLoop = new ExplorerLoop(this._goalManager, this._reflector, this._framework, {
1106
- tickInterval: this.config.tickInterval,
1107
- cooldownPeriod: this.config.cooldownPeriod
1108
- })
1109
- this._explorerLoop.start()
1110
-
1111
- // 注册工具
1112
- this._registerTools(framework)
1113
-
1114
- console.log('[Ambient] 插件已启动')
1115
- return this
1116
- }
1117
-
1118
- _registerTools(framework) {
1119
- // ambient_goals - 列出/创建/更新/删除目标
1120
- framework.registerTool({
1121
- name: 'ambient_goals',
1122
- description: '管理Ambient Agent目标 - 列出、创建、更新、删除、激活目标',
1123
- inputSchema: z.object({
1124
- action: z.enum(['list', 'create', 'update', 'delete', 'activate']).describe('执行的操作'),
1125
- goalId: z.string().optional().describe('目标ID(更新/删除/激活时必需)'),
1126
- title: z.string().optional().describe('目标标题(创建/更新时使用)'),
1127
- description: z.string().optional().describe('目标描述(创建/更新时使用)'),
1128
- priority: z.number().optional().describe('优先级1-10,数值越高越重要(创建/更新时使用)'),
1129
- actions: z.array(z.object({
1130
- id: z.string().optional().describe('操作标识符'),
1131
- type: z.enum(['tool', 'message', 'think']).describe('操作类型'),
1132
- name: z.string().optional().describe('工具名称(tool类型时使用)'),
1133
- args: z.record(z.any()).optional().describe('工具参数(tool类型时使用)'),
1134
- content: z.string().optional().describe('消息内容(message类型时使用)'),
1135
- topic: z.string().optional().describe('思考主题(think类型时使用)'),
1136
- mode: z.enum(['reflect', 'brainstorm', 'analyze', 'plan']).optional().describe('思考模式(think类型时使用)')
1137
- })).optional().describe('要执行的操作列表(创建/更新时使用)'),
1138
- conditions: z.object({
1139
- events: z.union([z.string(), z.array(z.string())]).optional().describe('要监听的事件类型'),
1140
- toolNames: z.union([z.string(), z.array(z.string())]).optional().describe('按工具名称过滤')
1141
- }).optional().describe('激活条件(创建/更新时使用)')
1142
- }),
1143
- execute: async (args) => {
1144
- return this._handleGoalsTool(args)
1145
- }
1146
- })
1147
-
1148
- // ambient_status - 获取当前循环状态
1149
- framework.registerTool({
1150
- name: 'ambient_status',
1151
- description: '获取当前Ambient Agent状态 - 循环状态、进行中的目标、最近活动',
1152
- inputSchema: z.object({}),
1153
- execute: async () => {
1154
- return this._handleStatusTool()
1155
- }
1156
- })
1157
-
1158
- // ambient_think - 触发主动LLM思考
1159
- framework.registerTool({
1160
- name: 'ambient_think',
1161
- description: '为某个目标触发主动LLM思考 - 模式:reflect(反思)、brainstorm(头脑风暴)、plan(计划)、analyze(分析)',
1162
- inputSchema: z.object({
1163
- goalId: z.string().optional().describe('要思考的目标ID'),
1164
- mode: z.enum(['reflect', 'brainstorm', 'plan', 'analyze']).describe('思考模式'),
1165
- topic: z.string().optional().describe('要思考的主题'),
1166
- depth: z.number().optional().describe('思考深度1-5')
1167
- }),
1168
- execute: async (args) => {
1169
- return this._handleThinkTool(args)
1170
- }
1171
- })
1172
-
1173
- // ambient_remember - 存储/检索/搜索持久化记忆
1174
- framework.registerTool({
1175
- name: 'ambient_remember',
1176
- description: '为Ambient Agent存储或检索持久化记忆',
1177
- inputSchema: z.object({
1178
- action: z.enum(['store', 'retrieve', 'search']).describe('操作:store存储记忆、retrieve检索最近、search搜索'),
1179
- content: z.string().optional().describe('记忆内容(store时使用)'),
1180
- key: z.string().optional().describe('记忆键(store/retrieve时使用)'),
1181
- query: z.string().optional().describe('搜索查询(search时使用)'),
1182
- limit: z.number().optional().describe('最大结果数(retrieve/search时使用)')
1183
- }),
1184
- execute: async (args) => {
1185
- return this._handleRememberTool(args)
1186
- }
1187
- })
1188
-
1189
- // ambient_control - 暂停/恢复/调整探索循环
1190
- framework.registerTool({
1191
- name: 'ambient_control',
1192
- description: '控制Ambient Agent探索循环 - 暂停、恢复或调整设置',
1193
- inputSchema: z.object({
1194
- action: z.enum(['pause', 'resume', 'status', 'adjust']).describe('控制操作'),
1195
- tickInterval: z.number().optional().describe('新的tick间隔毫秒数(adjust时使用)'),
1196
- cooldownPeriod: z.number().optional().describe('新的冷却时间毫秒数(adjust时使用)')
1197
- }),
1198
- execute: async (args) => {
1199
- return this._handleControlTool(args)
1200
- }
1201
- })
1202
- }
1203
-
1204
- _handleGoalsTool(args) {
1205
- const { action, goalId, title, description, priority, actions, conditions } = args
1206
-
1207
- switch (action) {
1208
- case 'list': {
1209
- const allGoals = this._goalManager.getAllGoals()
1210
- return {
1211
- success: true,
1212
- goals: allGoals.map(g => ({
1213
- id: g.id,
1214
- title: g.title,
1215
- state: g.state,
1216
- priority: g.priority,
1217
- actionsCount: g.actions ? g.actions.length : 0,
1218
- attempts: g.attempts,
1219
- createdAt: g.createdAt,
1220
- activatedAt: g.activatedAt,
1221
- completedAt: g.completedAt,
1222
- failedAt: g.failedAt
1223
- })),
1224
- total: allGoals.length,
1225
- active: this._goalManager.getActiveGoals().length,
1226
- pending: this._goalManager.getPendingGoals().length
1227
- }
1228
- }
1229
-
1230
- case 'create': {
1231
- if (!title) {
1232
- return { success: false, error: '创建目标需要提供标题' }
1233
- }
1234
- const goal = this._goalManager.createGoal({ title, description, priority, actions, conditions })
1235
- return { success: true, goal }
1236
- }
1237
-
1238
- case 'update': {
1239
- if (!goalId) {
1240
- return { success: false, error: '更新目标需要提供目标ID' }
1241
- }
1242
- const updates = {}
1243
- if (title !== undefined) updates.title = title
1244
- if (description !== undefined) updates.description = description
1245
- if (priority !== undefined) updates.priority = priority
1246
- if (actions !== undefined) updates.actions = actions
1247
- if (conditions !== undefined) updates.conditions = conditions
1248
- const goal = this._goalManager.updateGoal(goalId, updates)
1249
- return goal ? { success: true, goal } : { success: false, error: '目标未找到' }
1250
- }
1251
-
1252
- case 'delete': {
1253
- if (!goalId) {
1254
- return { success: false, error: '删除目标需要提供目标ID' }
1255
- }
1256
- const deleted = this._goalManager.deleteGoal(goalId)
1257
- return { success: deleted }
1258
- }
1259
-
1260
- case 'activate': {
1261
- if (!goalId) {
1262
- return { success: false, error: '激活目标需要提供目标ID' }
1263
- }
1264
- const goal = this._goalManager.activateGoal(goalId)
1265
- return goal ? { success: true, goal } : { success: false, error: '目标未找到或不是待激活状态' }
1266
- }
1267
-
1268
- default:
1269
- return { success: false, error: `未知操作: ${action}` }
1270
- }
1271
- }
1272
-
1273
- _handleStatusTool() {
1274
- if (!this._explorerLoop) {
1275
- return { success: false, error: '探索循环未初始化' }
1276
- }
1277
-
1278
- const loopStatus = this._explorerLoop.getStatus()
1279
- const activeGoals = this._goalManager.getActiveGoals().map(g => ({
1280
- id: g.id,
1281
- title: g.title,
1282
- priority: g.priority,
1283
- attempts: g.attempts,
1284
- lastActionId: g.lastActionId
1285
- }))
1286
- const pendingGoals = this._goalManager.getPendingGoals().map(g => ({
1287
- id: g.id,
1288
- title: g.title,
1289
- priority: g.priority
1290
- }))
1291
-
1292
- return {
1293
- success: true,
1294
- loop: {
1295
- running: loopStatus.running,
1296
- tickCount: loopStatus.tickCount,
1297
- lastTick: loopStatus.lastTick,
1298
- tickInterval: this.config.tickInterval,
1299
- cooldownPeriod: this.config.cooldownPeriod
1300
- },
1301
- activeGoals,
1302
- pendingGoals,
1303
- recentActivities: loopStatus.recentActivities
1304
- }
1305
- }
1306
-
1307
- async _handleThinkTool(args) {
1308
- const { goalId, mode, topic, depth } = args
1309
-
1310
- // 获取活跃代理
1311
- const agent = this._getActiveAgent()
1312
- if (!agent) {
1313
- return { success: false, error: '没有可用的活跃代理' }
1314
- }
1315
-
1316
- // 构建思考提示
1317
- let prompt = ''
1318
- if (goalId) {
1319
- const goal = this._goalManager.getGoal(goalId)
1320
- if (goal) {
1321
- prompt = this._buildGoalThinkPrompt(goal, mode, topic)
1322
- } else {
1323
- return { success: false, error: '目标未找到' }
1324
- }
1325
- } else {
1326
- prompt = this._buildFreeThinkPrompt(mode, topic)
1327
- }
1328
-
1329
- // 如果代理忙,等待其变为可用
1330
- let attempts = 0
1331
- const maxWaitAttempts = 10
1332
- const waitInterval = 500
1333
-
1334
- while (agent._status === 'busy' && attempts < maxWaitAttempts) {
1335
- console.log('[Ambient] 代理忙,等待中...')
1336
- await new Promise(resolve => setTimeout(resolve, waitInterval))
1337
- attempts++
1338
- }
1339
-
1340
- if (agent._status === 'busy') {
1341
- return {
1342
- success: false,
1343
- error: '代理繁忙,无法及时变为可用。请稍后重试。',
1344
- queued: true
1345
- }
1346
- }
1347
-
1348
- // 通过代理执行思考
1349
- const thinkPlugin = this._framework.pluginManager.get('think')
1350
- if (thinkPlugin) {
1351
- const result = await thinkPlugin._triggerThinking({ topic: prompt, mode, depth: depth || 2 })
1352
- // 如果结果提示繁忙,返回更友好的消息
1353
- if (result && result.message && result.message.includes && result.message.includes('busy')) {
1354
- return {
1355
- success: true,
1356
- queued: true,
1357
- message: '思考请求已排队,将在代理空闲时处理。'
1358
- }
1359
- }
1360
- return result
1361
- }
1362
-
1363
- // 备用:直接推送消息
1364
- return agent.pushMessage(prompt).then(result => ({
1365
- success: true,
1366
- result: typeof result === 'string' ? result : JSON.stringify(result)
1367
- })).catch(err => ({
1368
- success: false,
1369
- error: err.message
1370
- }))
1371
- }
1372
-
1373
- _buildGoalThinkPrompt(goal, mode, topic) {
1374
- const modePrompts = {
1375
- reflect: `作为Ambient Agent,反思当前目标:
1376
- 标题: ${goal.title}
1377
- 描述: ${goal.description || '无'}
1378
- 优先级: ${goal.priority}
1379
- 状态: ${goal.state}
1380
- 尝试次数: ${goal.attempts}
1381
-
1382
- ${topic ? `额外关注点: ${topic}` : ''}
1383
-
1384
- 请反思:
1385
- 1. 这个目标仍然相关且可实现吗?
1386
- 2. 操作是否适合这个目标?
1387
- 3.有什么可以改进的?`,
1388
- brainstorm: `为Ambient Agent目标头脑风暴新方法:
1389
- 标题: ${goal.title}
1390
- ${goal.description ? `描述: ${goal.description}` : ''}
1391
- 计划的操作数: ${goal.actions ? goal.actions.length : 0}
1392
-
1393
- ${topic ? `关注点: ${topic}` : '生成关于如何更有效地追求这个目标的新想法。'}`,
1394
- plan: `为Ambient Agent目标制定更精细的计划:
1395
- 标题: ${goal.title}
1396
- ${goal.description ? `描述: ${goal.description}` : ''}
1397
- ${topic ? `额外上下文: ${topic}` : ''}
1398
-
1399
- 制定一个清晰、可操作的计划。`,
1400
- analyze: `分析Ambient Agent目标:
1401
- 标题: ${goal.title}
1402
- 状态: ${goal.state}
1403
- 优先级: ${goal.priority}
1404
- 操作: ${goal.actions ? JSON.stringify(goal.actions) : '无'}
1405
-
1406
- ${topic ? `分析重点: ${topic}` : '这个目标的优势、劣势和潜在问题是什么?'}`
1407
- }
1408
- return modePrompts[mode] || modePrompts.reflect
1409
- }
1410
-
1411
- _buildFreeThinkPrompt(mode, topic) {
1412
- const modePrompts = {
1413
- reflect: `Ambient Agent反思: ${topic || '思考系统和目标的当前状态。有什么可以改进的?'}`,
1414
- brainstorm: `Ambient Agent头脑风暴: ${topic || '生成关于新目标或方法的有创意想法。'}`,
1415
- plan: `Ambient Agent计划: ${topic || '为待实现的目标制定计划。'}`,
1416
- analyze: `Ambient Agent分析: ${topic || '分析当前目标及其进展。'}`
1417
- }
1418
- return modePrompts[mode] || modePrompts.reflect
1419
- }
1420
-
1421
- _handleRememberTool(args) {
1422
- const { action, content, key, query, limit } = args
1423
- const maxResults = limit || 10
1424
-
1425
- switch (action) {
1426
- case 'store': {
1427
- if (!content) {
1428
- return { success: false, error: '存储需要提供内容' }
1429
- }
1430
- const memoryKey = key || `memory_${Date.now()}`
1431
- const memory = {
1432
- key: memoryKey,
1433
- content,
1434
- timestamp: new Date()
1435
- }
1436
- this._memories.push(memory)
1437
- this._stateStore.saveMemories(this._memories)
1438
- return { success: true, memory }
1439
- }
1440
-
1441
- case 'retrieve': {
1442
- const memories = this._memories.slice(-maxResults).reverse()
1443
- return {
1444
- success: true,
1445
- memories,
1446
- total: this._memories.length
1447
- }
1448
- }
1449
-
1450
- case 'search': {
1451
- if (!query) {
1452
- return { success: false, error: '搜索需要提供查询词' }
1453
- }
1454
- const queryLower = query.toLowerCase()
1455
- const results = this._memories
1456
- .filter(m => m.content.toLowerCase().includes(queryLower))
1457
- .slice(-maxResults)
1458
- .reverse()
1459
- return {
1460
- success: true,
1461
- results,
1462
- total: results.length
1463
- }
1464
- }
1465
-
1466
- default:
1467
- return { success: false, error: `未知操作: ${action}` }
1468
- }
1469
- }
1470
-
1471
- _handleControlTool(args) {
1472
- const { action, tickInterval, cooldownPeriod } = args
1473
-
1474
- switch (action) {
1475
- case 'pause': {
1476
- if (!this._explorerLoop) {
1477
- return { success: false, error: '探索循环未初始化' }
1478
- }
1479
- this._explorerLoop.pause()
1480
- return { success: true, message: '探索循环已暂停' }
1481
- }
1482
-
1483
- case 'resume': {
1484
- if (!this._explorerLoop) {
1485
- return { success: false, error: '探索循环未初始化' }
1486
- }
1487
- this._explorerLoop.resume()
1488
- return { success: true, message: '探索循环已恢复' }
1489
- }
1490
-
1491
- case 'status': {
1492
- if (!this._explorerLoop) {
1493
- return { success: false, error: '探索循环未初始化' }
1494
- }
1495
- const status = this._explorerLoop.getStatus()
1496
- return {
1497
- success: true,
1498
- running: status.running,
1499
- tickCount: status.tickCount,
1500
- lastTick: status.lastTick,
1501
- tickInterval: this.config.tickInterval,
1502
- cooldownPeriod: this.config.cooldownPeriod
1503
- }
1504
- }
1505
-
1506
- case 'adjust': {
1507
- if (tickInterval) {
1508
- this.config.tickInterval = tickInterval
1509
- }
1510
- if (cooldownPeriod) {
1511
- this.config.cooldownPeriod = cooldownPeriod
1512
- }
1513
- return {
1514
- success: true,
1515
- message: '设置已调整',
1516
- tickInterval: this.config.tickInterval,
1517
- cooldownPeriod: this.config.cooldownPeriod
1518
- }
1519
- }
1520
-
1521
- default:
1522
- return { success: false, error: `未知操作: ${action}` }
1523
- }
1524
- }
1525
-
1526
- _getActiveAgent() {
1527
- if (this._framework._mainAgent) {
1528
- return this._framework._mainAgent
1529
- }
1530
- const agents = this._framework._agents || []
1531
- return agents.length > 0 ? agents[agents.length - 1] : null
1532
- }
1533
-
1534
- reload(framework) {
1535
- this._framework = framework
1536
- if (this._explorerLoop && this._explorerLoop.isRunning()) {
1537
- // 用新的框架引用重新启动
1538
- this._eventWatcher = new EventWatcher(this._goalManager, this._framework)
1539
- this._eventWatcher.start()
1540
- }
1541
- }
1542
-
1543
- uninstall(framework) {
1544
- // 停止探索循环
1545
- if (this._explorerLoop) {
1546
- this._explorerLoop.stop()
1547
- this._explorerLoop = null
1548
- }
1549
-
1550
- // 停止事件监听器
1551
- if (this._eventWatcher) {
1552
- this._eventWatcher.stop()
1553
- this._eventWatcher = null
1554
- }
1555
-
1556
- // 清除引用
1557
- this._framework = null
1558
- this._goalManager = null
1559
- this._reflector = null
1560
- this._stateStore = null
1561
- this._memories = []
1562
- }
1563
- }
1564
-
1565
- module.exports = { AmbientAgentPlugin, GoalState }