foliko 1.0.63 → 1.0.65

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.
@@ -1,320 +1,195 @@
1
1
  /**
2
- * Ambient Agent Plugin v2 — 自主执行引擎
3
- *
4
- * 核心改造:
5
- * 1. DecisionEngine — 用 LLM 推理替代 FIFO 队列,动态决策下一步
6
- * 2. PriorityScheduler — 多维优先级排序(优先级 + 紧迫性 + 事件权重)
7
- * 3. ContextBuilder — 为每次 LLM 决策聚合完整上下文
8
- * 4. SemanticMemory — 关键词索引 + 时间衰减的记忆系统
9
- * 5. Reflector v2 — 失败分类 + 差异化恢复策略
2
+ * Ambient Agent 插件
3
+ * 持续后台运行的智能代理,监控事件并主动执行操作
10
4
  */
11
5
 
12
6
  const { Plugin } = require('../src/core/plugin-base')
13
7
  const { z } = require('zod')
14
8
  const fs = require('fs')
15
9
  const path = require('path')
16
- const crypto = require('crypto')
17
-
18
- // ─────────────────────────────────────────────────────────────────────────────
19
- // 常量
20
- // ─────────────────────────────────────────────────────────────────────────────
21
10
 
11
+ // 目标生命周期状态
22
12
  const GoalState = {
23
- PENDING: 'pending',
24
- ACTIVE: 'active',
25
- COMPLETED: 'completed',
26
- FAILED: 'failed',
27
- PAUSED: 'paused' // 新增:可暂停单个目标
28
- }
29
-
30
- const FailureType = {
31
- TOOL_NOT_FOUND: 'tool_not_found',
32
- EXECUTION_ERROR: 'execution_error',
33
- TIMEOUT: 'timeout',
34
- LOOP_DETECTED: 'loop_detected',
35
- MAX_ATTEMPTS: 'max_attempts',
36
- LLM_REFUSED: 'llm_refused'
13
+ PENDING: 'pending', // 待激活
14
+ ACTIVE: 'active', // 执行中
15
+ COMPLETED: 'completed', // 已完成
16
+ FAILED: 'failed' // 已失败
37
17
  }
38
18
 
19
+ // 生成唯一ID
39
20
  function generateId() {
40
- return crypto.randomUUID ? crypto.randomUUID() : `id_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`
21
+ if (require('crypto').randomUUID) {
22
+ return require('crypto').randomUUID()
23
+ }
24
+ return `goal_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
41
25
  }
42
26
 
43
- // ─────────────────────────────────────────────────────────────────────────────
44
- // StateStore 持久化(同原版,增加 executionLog)
45
- // ─────────────────────────────────────────────────────────────────────────────
46
-
27
+ // ============================================================================
28
+ // StateStore - 持久化目标和记忆到 .agent/data/ambient/*.json
29
+ // ============================================================================
47
30
  class StateStore {
48
31
  constructor(persistencePath) {
49
- this._path = persistencePath
32
+ this._persistencePath = persistencePath
50
33
  this._ensureDir()
51
34
  }
52
35
 
53
36
  _ensureDir() {
54
- if (!fs.existsSync(this._path)) fs.mkdirSync(this._path, { recursive: true })
55
- }
56
-
57
- _file(name) { return path.join(this._path, `${name}.json`) }
58
-
59
- _save(name, data) {
60
- try { fs.writeFileSync(this._file(name), JSON.stringify(data, null, 2)) }
61
- catch (e) { console.error(`[Ambient] save ${name} failed:`, e.message) }
37
+ if (!fs.existsSync(this._persistencePath)) {
38
+ fs.mkdirSync(this._persistencePath, { recursive: true })
39
+ }
62
40
  }
63
41
 
64
- _load(name, fallback) {
65
- try {
66
- const f = this._file(name)
67
- if (fs.existsSync(f)) return JSON.parse(fs.readFileSync(f, 'utf-8'))
68
- } catch (e) { console.error(`[Ambient] load ${name} failed:`, e.message) }
69
- return fallback
42
+ _getGoalsPath() {
43
+ return path.join(this._persistencePath, 'goals.json')
70
44
  }
71
45
 
72
- saveGoals(goals) { this._save('goals', goals) }
73
- loadGoals() { return this._load('goals', []) }
74
- saveMemories(mems) { this._save('memories', mems) }
75
- loadMemories() { return this._load('memories', []) }
76
- appendLog(entry) {
77
- const logs = this._load('execution_log', [])
78
- logs.push(entry)
79
- // 只保留最近 500 条
80
- this._save('execution_log', logs.slice(-500))
46
+ _getMemoriesPath() {
47
+ return path.join(this._persistencePath, 'memories.json')
81
48
  }
82
- loadLog() { return this._load('execution_log', []) }
83
- }
84
-
85
- // ─────────────────────────────────────────────────────────────────────────────
86
- // SemanticMemory — 替代原始 memories[] 数组
87
- // 支持:关键词索引检索 · 时间衰减评分 · 工作记忆(临时,不持久)
88
- // ─────────────────────────────────────────────────────────────────────────────
89
49
 
90
- class SemanticMemory {
91
- constructor(stateStore) {
92
- this._store = stateStore
93
- this._long = stateStore.loadMemories() // 长期记忆(持久化)
94
- this._working = [] // 工作记忆(会话内临时)
50
+ saveGoals(goals) {
51
+ try {
52
+ fs.writeFileSync(this._getGoalsPath(), JSON.stringify(goals, null, 2))
53
+ } catch (err) {
54
+ console.error('[Ambient] 保存目标失败:', err.message)
55
+ }
95
56
  }
96
57
 
97
- /**
98
- * 存储记忆
99
- * @param {string} content
100
- * @param {object} opts { key, tags, scope:'long'|'working', goalId }
101
- */
102
- store(content, opts = {}) {
103
- const { key, tags = [], scope = 'long', goalId } = opts
104
- const mem = {
105
- id: generateId(),
106
- key: key || `mem_${Date.now()}`,
107
- content,
108
- tags,
109
- goalId,
110
- createdAt: Date.now(),
111
- accessCount: 0
112
- }
113
- if (scope === 'working') {
114
- this._working.push(mem)
115
- if (this._working.length > 50) this._working.shift()
116
- } else {
117
- this._long.push(mem)
118
- if (this._long.length > 2000) {
119
- // 淘汰:访问次数最少 + 最旧的
120
- this._long.sort((a, b) => (a.accessCount - b.accessCount) || (a.createdAt - b.createdAt))
121
- this._long = this._long.slice(-1800)
58
+ loadGoals() {
59
+ try {
60
+ const filePath = this._getGoalsPath()
61
+ if (fs.existsSync(filePath)) {
62
+ const data = fs.readFileSync(filePath, 'utf-8')
63
+ return JSON.parse(data)
122
64
  }
123
- this._store.saveMemories(this._long)
65
+ } catch (err) {
66
+ console.error('[Ambient] 加载目标失败:', err.message)
124
67
  }
125
- return mem
68
+ return []
126
69
  }
127
70
 
128
- /**
129
- * 检索记忆(关键词 + 时间衰减评分)
130
- * @param {string} query
131
- * @param {object} opts { limit, scope, goalId, tags }
132
- */
133
- search(query, opts = {}) {
134
- const { limit = 10, scope = 'all', goalId, tags } = opts
135
- const queryTerms = query.toLowerCase().split(/\s+/).filter(Boolean)
136
- const now = Date.now()
137
- const DAY = 86400000
138
-
139
- const pool = scope === 'working'
140
- ? this._working
141
- : scope === 'long'
142
- ? this._long
143
- : [...this._working, ...this._long]
144
-
145
- const scored = pool
146
- .filter(m => {
147
- if (goalId && m.goalId !== goalId) return false
148
- if (tags && tags.length > 0 && !tags.some(t => m.tags.includes(t))) return false
149
- return true
150
- })
151
- .map(m => {
152
- const text = m.content.toLowerCase()
153
- const hits = queryTerms.filter(t => text.includes(t)).length
154
- const ratio = hits / Math.max(queryTerms.length, 1)
155
- // 时间衰减:7 天半衰期
156
- const ageDays = (now - m.createdAt) / DAY
157
- const timeFactor = Math.exp(-ageDays / 7)
158
- // 访问热度加成
159
- const hotFactor = 1 + Math.log1p(m.accessCount) * 0.1
160
- return { mem: m, score: ratio * timeFactor * hotFactor }
161
- })
162
- .filter(s => s.score > 0)
163
- .sort((a, b) => b.score - a.score)
164
- .slice(0, limit)
165
-
166
- // 更新访问计数
167
- scored.forEach(({ mem }) => {
168
- mem.accessCount++
169
- if (this._long.includes(mem)) this._store.saveMemories(this._long)
170
- })
171
-
172
- return scored.map(s => s.mem)
71
+ saveMemories(memories) {
72
+ try {
73
+ fs.writeFileSync(this._getMemoriesPath(), JSON.stringify(memories, null, 2))
74
+ } catch (err) {
75
+ console.error('[Ambient] 保存记忆失败:', err.message)
76
+ }
173
77
  }
174
78
 
175
- /** 获取最近 N 条 */
176
- recent(limit = 10, scope = 'all') {
177
- const pool = scope === 'working'
178
- ? this._working
179
- : scope === 'long'
180
- ? this._long
181
- : [...this._working, ...this._long]
182
- return [...pool].sort((a, b) => b.createdAt - a.createdAt).slice(0, limit)
79
+ loadMemories() {
80
+ try {
81
+ const filePath = this._getMemoriesPath()
82
+ if (fs.existsSync(filePath)) {
83
+ const data = fs.readFileSync(filePath, 'utf-8')
84
+ return JSON.parse(data)
85
+ }
86
+ } catch (err) {
87
+ console.error('[Ambient] 加载记忆失败:', err.message)
88
+ }
89
+ return []
183
90
  }
184
-
185
- getAll() { return { long: this._long, working: this._working } }
186
- clearWorking() { this._working = [] }
187
91
  }
188
92
 
189
- // ─────────────────────────────────────────────────────────────────────────────
190
- // GoalManager 增强版(支持子目标)
191
- // ─────────────────────────────────────────────────────────────────────────────
192
-
93
+ // ============================================================================
94
+ // GoalManager - 管理目标及其生命周期状态
95
+ // ============================================================================
193
96
  class GoalManager {
194
97
  constructor(stateStore) {
195
98
  this._goals = new Map()
196
- this._store = stateStore
197
- this._load()
99
+ this._stateStore = stateStore
100
+ this._loadGoals()
198
101
  }
199
102
 
200
- _load() {
201
- for (const g of this._store.loadGoals()) this._goals.set(g.id, g)
103
+ _loadGoals() {
104
+ const savedGoals = this._stateStore.loadGoals()
105
+ for (const goal of savedGoals) {
106
+ this._goals.set(goal.id, goal)
107
+ }
202
108
  }
203
109
 
204
110
  _persist() {
205
- this._store.saveGoals(Array.from(this._goals.values()))
111
+ const goalsArray = Array.from(this._goals.values())
112
+ this._stateStore.saveGoals(goalsArray)
206
113
  }
207
114
 
208
- createGoal(data, parentId = null) {
115
+ createGoal(goalData) {
209
116
  const goal = {
210
- id: generateId(),
211
- title: data.title || 'Untitled',
212
- description: data.description || '',
213
- priority: data.priority ?? 5,
214
- state: GoalState.PENDING,
215
- parentId, // 支持子目标树
216
- subGoalIds: [],
217
- // 行动模板(LLM 可参考,但不再强制按序执行)
218
- actionHints: data.actions || [],
219
- conditions: data.conditions || {},
220
- successCriteria: data.successCriteria || '',
221
- createdAt: Date.now(),
222
- updatedAt: Date.now(),
223
- activatedAt: null,
224
- completedAt: null,
225
- failedAt: null,
226
- attempts: 0,
227
- maxAttempts: data.maxAttempts || 15,
228
- eventsReceived: [],
229
- executionHistory: [], // 每次决策记录
230
- lastDecisionAt: null
117
+ id: generateId(),
118
+ title: goalData.title || '未命名目标',
119
+ description: goalData.description || '',
120
+ priority: goalData.priority || 5,
121
+ state: GoalState.PENDING,
122
+ actions: goalData.actions || [],
123
+ conditions: goalData.conditions || {},
124
+ createdAt: new Date(),
125
+ updatedAt: new Date(),
126
+ activatedAt: null,
127
+ completedAt: null,
128
+ failedAt: null,
129
+ attempts: 0,
130
+ maxAttempts: goalData.maxAttempts || 10,
131
+ consecutiveSameActions: 0,
132
+ lastActionId: null,
133
+ eventsReceived: []
231
134
  }
232
135
  this._goals.set(goal.id, goal)
233
- if (parentId) {
234
- const parent = this._goals.get(parentId)
235
- if (parent) {
236
- parent.subGoalIds.push(goal.id)
237
- parent.updatedAt = Date.now()
238
- }
239
- }
240
136
  this._persist()
241
137
  return goal
242
138
  }
243
139
 
244
- getGoal(id) { return this._goals.get(id) }
245
- getAllGoals() { return Array.from(this._goals.values()) }
246
- getActiveGoals() { return this.getAllGoals().filter(g => g.state === GoalState.ACTIVE) }
247
- getPendingGoals() { return this.getAllGoals().filter(g => g.state === GoalState.PENDING) }
140
+ getGoal(id) {
141
+ return this._goals.get(id)
142
+ }
248
143
 
249
- updateGoal(id, updates) {
250
- const g = this._goals.get(id)
251
- if (!g) return null
252
- Object.assign(g, updates, { updatedAt: Date.now() })
253
- this._persist()
254
- return g
144
+ getAllGoals() {
145
+ return Array.from(this._goals.values())
255
146
  }
256
147
 
257
- activateGoal(id) {
258
- const g = this._goals.get(id)
259
- if (!g || g.state !== GoalState.PENDING) return null
260
- g.state = GoalState.ACTIVE
261
- g.activatedAt = Date.now()
262
- g.updatedAt = Date.now()
263
- this._persist()
264
- return g
148
+ getActiveGoals() {
149
+ return Array.from(this._goals.values()).filter(g => g.state === GoalState.ACTIVE)
265
150
  }
266
151
 
267
- completeGoal(id) {
268
- const g = this._goals.get(id)
269
- if (!g) return null
270
- g.state = GoalState.COMPLETED
271
- g.completedAt = Date.now()
272
- g.updatedAt = Date.now()
152
+ getPendingGoals() {
153
+ return Array.from(this._goals.values()).filter(g => g.state === GoalState.PENDING)
154
+ }
155
+
156
+ updateGoal(id, updates) {
157
+ const goal = this._goals.get(id)
158
+ if (!goal) return null
159
+ Object.assign(goal, updates, { updatedAt: new Date() })
273
160
  this._persist()
274
- // 自动检查父目标:若所有子目标完成则触发回调
275
- if (g.parentId) {
276
- const parent = this._goals.get(g.parentId)
277
- if (parent) {
278
- const allDone = parent.subGoalIds.every(sid => {
279
- const sub = this._goals.get(sid)
280
- return sub && sub.state === GoalState.COMPLETED
281
- })
282
- if (allDone && parent.state === GoalState.ACTIVE) {
283
- this.completeGoal(parent.id)
284
- }
285
- }
286
- }
287
- return g
161
+ return goal
288
162
  }
289
163
 
290
- failGoal(id, reason, type = FailureType.EXECUTION_ERROR) {
291
- const g = this._goals.get(id)
292
- if (!g) return null
293
- g.state = GoalState.FAILED
294
- g.failedAt = Date.now()
295
- g.failureReason = reason
296
- g.failureType = type
297
- g.updatedAt = Date.now()
164
+ activateGoal(id) {
165
+ const goal = this._goals.get(id)
166
+ if (!goal || goal.state !== GoalState.PENDING) return null
167
+ goal.state = GoalState.ACTIVE
168
+ goal.activatedAt = new Date()
169
+ goal.updatedAt = new Date()
298
170
  this._persist()
299
- return g
171
+ return goal
300
172
  }
301
173
 
302
- pauseGoal(id) {
303
- const g = this._goals.get(id)
304
- if (!g || g.state !== GoalState.ACTIVE) return null
305
- g.state = GoalState.PAUSED
306
- g.updatedAt = Date.now()
174
+ completeGoal(id) {
175
+ const goal = this._goals.get(id)
176
+ if (!goal) return null
177
+ goal.state = GoalState.COMPLETED
178
+ goal.completedAt = new Date()
179
+ goal.updatedAt = new Date()
307
180
  this._persist()
308
- return g
181
+ return goal
309
182
  }
310
183
 
311
- resumeGoal(id) {
312
- const g = this._goals.get(id)
313
- if (!g || g.state !== GoalState.PAUSED) return null
314
- g.state = GoalState.ACTIVE
315
- g.updatedAt = Date.now()
184
+ failGoal(id, reason) {
185
+ const goal = this._goals.get(id)
186
+ if (!goal) return null
187
+ goal.state = GoalState.FAILED
188
+ goal.failedAt = new Date()
189
+ goal.failureReason = reason
190
+ goal.updatedAt = new Date()
316
191
  this._persist()
317
- return g
192
+ return goal
318
193
  }
319
194
 
320
195
  deleteGoal(id) {
@@ -324,595 +199,209 @@ class GoalManager {
324
199
  }
325
200
 
326
201
  addEventToGoal(goalId, event) {
327
- const g = this._goals.get(goalId)
328
- if (!g) return
329
- g.eventsReceived.push({ type: event.type, data: event.data, ts: Date.now() })
330
- // 只保留最近 20 个事件
331
- if (g.eventsReceived.length > 20) g.eventsReceived = g.eventsReceived.slice(-20)
332
- this._persist()
333
- }
334
-
335
- recordDecision(goalId, decision) {
336
- const g = this._goals.get(goalId)
337
- if (!g) return
338
- g.executionHistory.push({ ...decision, ts: Date.now() })
339
- if (g.executionHistory.length > 50) g.executionHistory = g.executionHistory.slice(-50)
340
- g.lastDecisionAt = Date.now()
341
- g.updatedAt = Date.now()
202
+ const goal = this._goals.get(goalId)
203
+ if (!goal) return
204
+ goal.eventsReceived.push({
205
+ event: event.event || event.type,
206
+ timestamp: new Date()
207
+ })
342
208
  this._persist()
343
209
  }
344
210
  }
345
211
 
346
- // ─────────────────────────────────────────────────────────────────────────────
347
- // PriorityScheduler 多维优先级排序
348
- // ─────────────────────────────────────────────────────────────────────────────
349
-
350
- class PriorityScheduler {
351
- /**
352
- * 从活跃目标中选出本次 tick 应处理的目标列表
353
- * 评分维度:用户优先级 + 待处理事件数 + 等待时间 + 子目标阻塞
354
- */
355
- schedule(goals) {
356
- const now = Date.now()
357
-
358
- return goals
359
- .filter(g => g.state === GoalState.ACTIVE)
360
- .map(g => {
361
- // 1. 用户设定优先级(1-10)
362
- const userPriority = (g.priority || 5) * 10
363
-
364
- // 2. 待处理事件加权(有事件的目标应优先处理)
365
- const eventBoost = Math.min((g.eventsReceived || []).length * 15, 60)
366
-
367
- // 3. 等待时间加成(防止饥饿)
368
- const waitMs = g.lastDecisionAt ? now - g.lastDecisionAt : now - (g.activatedAt || now)
369
- const waitBoost = Math.min(waitMs / 60000, 20) // 最多加 20 分,单位:分钟
370
-
371
- // 4. 父目标降权(应先完成子目标)
372
- const parentPenalty = (g.subGoalIds && g.subGoalIds.length > 0) ? -10 : 0
373
-
374
- const score = userPriority + eventBoost + waitBoost + parentPenalty
375
- return { goal: g, score }
376
- })
377
- .sort((a, b) => b.score - a.score)
378
- .map(s => s.goal)
379
- }
380
- }
381
-
382
- // ─────────────────────────────────────────────────────────────────────────────
383
- // ContextBuilder — 为 LLM 决策聚合上下文
384
- // ─────────────────────────────────────────────────────────────────────────────
385
-
386
- class ContextBuilder {
387
- constructor(memory, goalManager) {
388
- this._memory = memory
212
+ // ============================================================================
213
+ // EventWatcher - 订阅框架事件,筛选相关事件
214
+ // ============================================================================
215
+ class EventWatcher {
216
+ constructor(goalManager, framework) {
389
217
  this._goalManager = goalManager
218
+ this._framework = framework
219
+ this._handlers = []
220
+ this._relevantEvents = new Set([
221
+ 'tool:result', // 工具执行结果
222
+ 'scheduler:reminder', // 定时提醒
223
+ 'agent:message', // 代理消息
224
+ 'think:thought_completed', // 思考完成
225
+ 'email:received', // 收到邮件
226
+ 'webhook:received' // Webhook接收
227
+ ])
390
228
  }
391
229
 
392
- /**
393
- * 构建用于 DecisionEngine 的完整上下文
394
- */
395
- build(goal, availableTools) {
396
- // 1. 相关记忆
397
- const relevantMems = this._memory.search(
398
- `${goal.title} ${goal.description}`,
399
- { limit: 5, goalId: goal.id }
400
- )
401
-
402
- // 2. 最近决策历史
403
- const recentHistory = (goal.executionHistory || []).slice(-5)
404
-
405
- // 3. 待处理事件摘要
406
- const pendingEvents = (goal.eventsReceived || []).map(e => ({
407
- type: e.type,
408
- summary: this._summarizeEvent(e),
409
- ts: e.ts
410
- }))
411
-
412
- // 4. 可用工具列表(简化)
413
- const toolSummaries = availableTools.map(t => ({
414
- name: t.name,
415
- description: (t.description || '').slice(0, 100)
416
- }))
417
-
418
- // 5. 子目标状态
419
- const subGoals = (goal.subGoalIds || []).map(id => {
420
- const sub = this._goalManager.getGoal(id)
421
- return sub ? { id: sub.id, title: sub.title, state: sub.state } : null
422
- }).filter(Boolean)
423
-
424
- return {
425
- goal: {
426
- id: goal.id,
427
- title: goal.title,
428
- description: goal.description,
429
- priority: goal.priority,
430
- attempts: goal.attempts,
431
- maxAttempts: goal.maxAttempts,
432
- successCriteria: goal.successCriteria,
433
- actionHints: goal.actionHints || [],
434
- state: goal.state
435
- },
436
- pendingEvents,
437
- recentHistory,
438
- relevantMemories: relevantMems.map(m => m.content),
439
- subGoals,
440
- availableTools: toolSummaries
441
- }
442
- }
443
-
444
- _summarizeEvent(event) {
445
- if (!event.data) return event.type
446
- try {
447
- const d = event.data
448
- if (typeof d === 'string') return d.slice(0, 200)
449
- if (d.subject) return `邮件: ${d.subject}`
450
- if (d.message) return d.message.slice(0, 200)
451
- if (d.body) return d.body.slice(0, 200)
452
- return JSON.stringify(d).slice(0, 200)
453
- } catch { return String(event.data).slice(0, 200) }
454
- }
455
- }
456
-
457
- // ─────────────────────────────────────────────────────────────────────────────
458
- // DecisionEngine — 核心:LLM 推理决定下一步行动
459
- // 取代原版 ExplorerLoop 中的静态 FIFO 队列
460
- // ─────────────────────────────────────────────────────────────────────────────
461
-
462
- class DecisionEngine {
463
- constructor(framework, contextBuilder, goalManager, stateStore, config, agent) {
464
- this._framework = framework
465
- this._ctx = contextBuilder
466
- this._goalManager = goalManager
467
- this._store = stateStore
468
- this._config = config
469
- this._llmCallTimeout = config.llmCallTimeout || 60000
470
- this._agent = agent // 专用的 ambient agent
471
- }
472
-
473
- /**
474
- * 主入口:为指定目标做出决策并返回要执行的 action
475
- * @returns {{ action, reasoning, shouldComplete, shouldFail, failReason } | null}
476
- */
477
- async decide(goal) {
478
- const availableTools = this._framework.getTools ? this._framework.getTools() : []
479
- const context = this._ctx.build(goal, availableTools)
480
-
481
- // 构造 LLM prompt
482
- const prompt = this._buildDecisionPrompt(context)
483
-
484
- let llmResponse
485
- try {
486
- // 直接调用 LLM
487
- llmResponse = await this._callLLM(prompt)
488
- } catch (err) {
489
- console.warn('[Ambient] DecisionEngine LLM call failed:', err.message)
490
- // 降级:如果 LLM 不可用,回退到 actionHints 队列
491
- return this._fallbackDecision(goal)
492
- }
230
+ start() {
231
+ const events = [
232
+ ['tool:result', (data) => this._handleEvent('tool:result', data)],
233
+ ['scheduler:reminder', (data) => this._handleEvent('scheduler:reminder', data)],
234
+ ['agent:message', (data) => this._handleEvent('agent:message', data)],
235
+ ['think:thought_completed', (data) => this._handleEvent('think:thought_completed', data)],
236
+ ['scheduler:task_completed', (data) => this._handleEvent('scheduler:task_completed', data)],
237
+ ['scheduler:task_failed', (data) => this._handleEvent('scheduler:task_failed', data)],
238
+ ['email:received', (data) => this._handleEvent('email:received', data)],
239
+ ['webhook:received', (data) => this._handleEvent('webhook:received', data)]
240
+ ]
493
241
 
494
- // Agent 忙,跳过这次决策
495
- if (llmResponse === null) {
496
- return null
242
+ for (const [event, handler] of events) {
243
+ this._framework.on(event, handler)
244
+ this._handlers.push({ event, handler })
497
245
  }
498
-
499
- // 解析 LLM 返回的 JSON 决策
500
- const decision = this._parseDecision(llmResponse, goal)
501
-
502
- // 记录决策到目标历史
503
- this._goalManager.recordDecision(goal.id, {
504
- reasoning: decision.reasoning,
505
- action: decision.action,
506
- llmUsed: true
507
- })
508
-
509
- // 写入执行日志
510
- this._store.appendLog({
511
- type: 'decision',
512
- goalId: goal.id,
513
- goal: goal.title,
514
- decision,
515
- ts: Date.now()
516
- })
517
-
518
- return decision
519
246
  }
520
247
 
521
- /**
522
- * 构造决策 prompt
523
- */
524
- _buildDecisionPrompt(context) {
525
- const { goal, pendingEvents, recentHistory, relevantMemories, subGoals, availableTools } = context
526
-
527
- const eventsSection = pendingEvents.length > 0
528
- ? `\n待处理事件:\n${pendingEvents.map(e => ` - [${e.type}] ${e.summary}`).join('\n')}`
529
- : ''
530
-
531
- const historySection = recentHistory.length > 0
532
- ? `\n最近执行历史(避免重复):\n${recentHistory.map(h =>
533
- ` - ${h.reasoning || ''} → ${h.action ? h.action.type + ':' + (h.action.name || '') : '无行动'}`
534
- ).join('\n')}`
535
- : ''
536
-
537
- const memSection = relevantMemories.length > 0
538
- ? `\n相关记忆:\n${relevantMemories.map(m => ` - ${m}`).join('\n')}`
539
- : ''
540
-
541
- const subSection = subGoals.length > 0
542
- ? `\n子目标状态:\n${subGoals.map(s => ` - [${s.state}] ${s.title}`).join('\n')}`
543
- : ''
544
-
545
- const toolList = availableTools.map(t => ` - ${t.name}: ${t.description}`).join('\n')
546
-
547
- const hintSection = goal.actionHints.length > 0
548
- ? `\n行动参考(可选):\n${JSON.stringify(goal.actionHints, null, 2)}`
549
- : ''
550
-
551
- return `你是一个自主运行的 Agent,负责完成以下目标。
552
-
553
- ## 当前目标
554
- 标题:${goal.title}
555
- 描述:${goal.description}
556
- 优先级:${goal.priority}/10
557
- 已尝试:${goal.attempts}/${goal.maxAttempts} 次
558
- 成功标准:${goal.successCriteria || '完成目标描述中的任务'}
559
- ${eventsSection}${historySection}${memSection}${subSection}${hintSection}
560
-
561
- ## 可用工具
562
- ${toolList}
563
-
564
- ## 决策要求
565
- 请分析当前状态,决定**下一步最优行动**。你必须返回一个 JSON 对象(不含 markdown 代码块):
566
-
567
- {
568
- "reasoning": "简短说明为什么选择这个行动(1-2句)",
569
- "shouldComplete": false,
570
- "shouldFail": false,
571
- "failReason": "",
572
- "action": {
573
- "type": "tool | message | think | wait | create_subgoal",
574
- "name": "工具名(type=tool时必填)",
575
- "args": {},
576
- "content": "消息内容(type=message时)",
577
- "topic": "思考主题(type=think时)",
578
- "mode": "reflect | plan | analyze(type=think时)",
579
- "waitMs": 5000,
580
- "subGoal": {
581
- "title": "",
582
- "description": "",
583
- "priority": 5,
584
- "actions": []
248
+ stop() {
249
+ for (const { event, handler } of this._handlers) {
250
+ this._framework.off(event, handler)
585
251
  }
586
- }
587
- }
588
-
589
- 注意:
590
- - 如果目标已完成,设 shouldComplete=true,action 可为 null
591
- - 如果目标无法完成(缺少工具/权限/信息),设 shouldFail=true 并填写 failReason
592
- - 如果需要等待更多事件,action.type 设为 "wait"
593
- - 如果任务可以分解,优先用 create_subgoal 分解
594
- - 不要重复刚刚执行过的相同行动`
252
+ this._handlers = []
595
253
  }
596
254
 
597
- /**
598
- * 调用 LLM(使用专用的 ambient agent)
599
- */
600
- async _callLLM(prompt) {
601
- const agent = this._agent
602
- if (!agent) throw new Error('No ambient agent available')
603
-
604
- // 检查是否忙
605
- if (agent._status === 'busy') {
606
- throw new Error('busy')
607
- }
608
-
609
- try {
610
- // 直接调用 chat,不使用队列
611
- const result = await agent.chat(prompt)
612
- return typeof result === 'string' ? result : JSON.stringify(result)
613
- } catch (e) {
614
- if (e.message.includes('busy')) {
615
- // Agent 忙,跳过这次决策
616
- return null
255
+ _handleEvent(type, data) {
256
+ const activeGoals = this._goalManager.getActiveGoals()
257
+ for (const goal of activeGoals) {
258
+ // 检查目标条件是否匹配此事件
259
+ if (this._isRelevantToGoal(goal, type, data)) {
260
+ this._goalManager.addEventToGoal(goal.id, { type, data })
617
261
  }
618
- throw new Error('LLM call failed: ' + e.message)
619
262
  }
620
263
  }
621
264
 
622
- /**
623
- * 解析 LLM 返回的 JSON 决策
624
- */
625
- _parseDecision(raw, goal) {
626
- try {
627
- // 移除思考标签
628
- let text = (raw || '').replace(/<think>[\s\S]*?<\/think>/g, '')
629
-
630
- // 尝试提取 JSON 对象
631
- const jsonMatch = text.match(/\{[\s\S]*\}/)
632
- if (jsonMatch) {
633
- const parsed = JSON.parse(jsonMatch[0])
634
-
635
- // 检查是否是外层包装格式 { success: true, message: "{...}" }
636
- if (parsed.message && typeof parsed.message === 'string') {
637
- const innerText = parsed.message.replace(/<think>[\s\S]*?<\/think>/g, '')
638
- const innerMatch = innerText.match(/\{[\s\S]*\}/)
639
- if (innerMatch) {
640
- const inner = JSON.parse(innerMatch[0])
641
- return inner
642
- }
643
- }
644
-
645
- return parsed
265
+ _isRelevantToGoal(goal, eventType, data) {
266
+ // 检查条件中是否有明确的事件类型
267
+ if (goal.conditions && goal.conditions.events) {
268
+ const allowedEvents = Array.isArray(goal.conditions.events)
269
+ ? goal.conditions.events
270
+ : [goal.conditions.events]
271
+ if (!allowedEvents.includes(eventType)) {
272
+ return false
646
273
  }
647
-
648
- // 尝试移除 markdown 代码块
649
- const cleaned = text.replace(/```(?:json)?\n?/g, '').trim()
650
- if (cleaned.startsWith('{')) {
651
- const parsed = JSON.parse(cleaned)
652
- return parsed
653
- }
654
-
655
- throw new Error('No JSON found in response')
656
- } catch (e) {
657
- console.warn('[Ambient] Failed to parse LLM decision, using fallback:', e.message)
658
- return this._fallbackDecision(goal)
659
274
  }
660
- }
661
-
662
- /**
663
- * 降级决策:LLM 不可用时,回退到 actionHints 队列
664
- */
665
- _fallbackDecision(goal) {
666
- // actionHints 是文本提示,不是可执行的动作对象
667
- // 降级时应该等待,让 LLM 稍后重新决策
668
- return {
669
- reasoning: 'LLM 不可用或解析失败,等待一下再试',
670
- shouldComplete: false,
671
- shouldFail: false,
672
- action: { type: 'wait', waitMs: 5000 }
275
+ // 检查工具名称过滤器
276
+ if (goal.conditions && goal.conditions.toolNames) {
277
+ const toolNames = Array.isArray(goal.conditions.toolNames)
278
+ ? goal.conditions.toolNames
279
+ : [goal.conditions.toolNames]
280
+ if (data && data.toolName && !toolNames.includes(data.toolName)) {
281
+ return false
282
+ }
673
283
  }
284
+ return true
674
285
  }
675
286
  }
676
287
 
677
- // ─────────────────────────────────────────────────────────────────────────────
678
- // Reflector v2 — 失败分类 + 差异化恢复策略
679
- // ─────────────────────────────────────────────────────────────────────────────
680
-
288
+ // ============================================================================
289
+ // Reflector - 评估操作结果,更新目标状态
290
+ // ============================================================================
681
291
  class Reflector {
682
- constructor(goalManager, memory, stateStore) {
292
+ constructor(goalManager) {
683
293
  this._goalManager = goalManager
684
- this._memory = memory
685
- this._store = stateStore
686
294
  }
687
295
 
688
- /**
689
- * 评估行动结果,返回恢复策略
690
- */
691
- evaluate(goal, actionResult, decision) {
692
- const now = Date.now()
296
+ evaluateOutcome(goal, actionResult) {
297
+ if (!goal) return null
693
298
 
694
- // —— 成功路径 ——
695
- if (actionResult && actionResult.success !== false && !actionResult.error) {
299
+ // 检查错误
300
+ if (actionResult && actionResult.error) {
301
+ // 增加尝试次数但不立即失败
696
302
  goal.attempts++
697
- // 将结果摘要写入工作记忆
698
- this._memory.store(
699
- `[${goal.title}] 行动成功: ${decision.reasoning} → ${JSON.stringify(actionResult).slice(0, 200)}`,
700
- { scope: 'working', goalId: goal.id, tags: ['success'] }
701
- )
702
- this._store.appendLog({ type: 'action_success', goalId: goal.id, ts: now, result: String(actionResult).slice(0, 300) })
703
- return { status: 'continue', actionSucceeded: true }
704
- }
705
-
706
- // —— 失败路径:分类处理 ——
707
- goal.attempts++
708
- const errMsg = (actionResult && actionResult.error) ? actionResult.error : 'unknown error'
709
- const ftype = this._classifyError(errMsg, actionResult)
710
-
711
- this._memory.store(
712
- `[${goal.title}] 行动失败(${ftype}): ${errMsg.slice(0, 200)}`,
713
- { scope: 'working', goalId: goal.id, tags: ['failure', ftype] }
714
- )
715
- this._store.appendLog({ type: 'action_failure', goalId: goal.id, ftype, err: errMsg, ts: now })
716
-
717
- // 超出最大尝试次数
718
- if (goal.attempts >= goal.maxAttempts) {
719
- return { status: 'fail', reason: `超出最大尝试次数(${goal.maxAttempts})`, type: FailureType.MAX_ATTEMPTS }
303
+ return {
304
+ shouldContinue: goal.attempts < goal.maxAttempts,
305
+ actionTaken: false
306
+ }
720
307
  }
721
308
 
722
- // 不同错误类型的恢复策略
723
- switch (ftype) {
724
- case FailureType.TOOL_NOT_FOUND:
725
- // 工具不存在 → 立即失败,不重试
726
- return { status: 'fail', reason: `工具不存在: ${errMsg}`, type: ftype }
727
-
728
- case FailureType.TIMEOUT:
729
- // 超时 → 指数退避后重试
730
- return { status: 'retry', backoffMs: Math.min(5000 * Math.pow(2, goal.attempts), 60000) }
309
+ // 检查是否成功完成
310
+ if (actionResult && actionResult.success === true) {
311
+ goal.attempts++
731
312
 
732
- case FailureType.LLM_REFUSED:
733
- // LLM 拒绝 标记失败
734
- return { status: 'fail', reason: errMsg, type: ftype }
313
+ // 检查目标是否完成
314
+ if (goal.actions.length === 0 || goal.attempts >= goal.maxAttempts) {
315
+ return { shouldContinue: false, goalComplete: true }
316
+ }
735
317
 
736
- default:
737
- // 一般执行错误 → 继续,让 DecisionEngine 重新决策
738
- return { status: 'continue', actionSucceeded: false, error: errMsg }
318
+ return { shouldContinue: true, actionTaken: true }
739
319
  }
740
- }
741
-
742
- _classifyError(errMsg, result) {
743
- if (!errMsg) return FailureType.EXECUTION_ERROR
744
- const msg = errMsg.toLowerCase()
745
- if (msg.includes('not found') || msg.includes('no tool')) return FailureType.TOOL_NOT_FOUND
746
- if (msg.includes('timeout')) return FailureType.TIMEOUT
747
- if (msg.includes('refused') || msg.includes('not allowed')) return FailureType.LLM_REFUSED
748
- return FailureType.EXECUTION_ERROR
749
- }
750
- }
751
320
 
752
- // ─────────────────────────────────────────────────────────────────────────────
753
- // ActionExecutor — 执行层(增加超时控制)
754
- // ─────────────────────────────────────────────────────────────────────────────
755
-
756
- class ActionExecutor {
757
- constructor(framework, config) {
758
- this._framework = framework
759
- this._timeout = config.actionTimeout || 20000
760
- }
761
-
762
- async execute(action, eventData) {
763
- if (!action || !action.type) return { success: false, error: 'Invalid action' }
321
+ // 工具执行无错误 - 视为成功
322
+ goal.attempts++
764
323
 
765
- try {
766
- return await Promise.race([
767
- this._run(action, eventData),
768
- new Promise((_, rej) => setTimeout(() => rej(new Error('Action execution timeout')), this._timeout))
769
- ])
770
- } catch (err) {
771
- return { success: false, error: err.message }
324
+ // 检查目标是否完成(没有更多操作)
325
+ if (goal.actions.length === 0 || goal.attempts >= goal.maxAttempts) {
326
+ return { shouldContinue: false, goalComplete: true }
772
327
  }
773
- }
774
-
775
- async _run(action, eventData) {
776
- switch (action.type) {
777
- case 'tool': {
778
- if (!action.name) return { success: false, error: 'Tool name required' }
779
- const tools = this._framework.getTools ? this._framework.getTools() : []
780
- const tool = tools.find(t => t.name === action.name)
781
- if (!tool) return { success: false, error: `Tool not found: ${action.name}` }
782
- const args = { ...(action.args || {}) }
783
- if (eventData) args._event = eventData
784
- return tool.execute(args, this._framework)
785
- }
786
328
 
787
- case 'message': {
788
- const agent = this._getAgent()
789
- if (!agent) return { success: false, error: 'No active agent' }
790
- let content = action.content || ''
791
- if (eventData) content += `\n\n[Event: ${JSON.stringify(eventData).slice(0, 300)}]`
792
- const result = await agent.pushMessage(content)
793
- return { success: true, result }
794
- }
329
+ return { shouldContinue: true, actionTaken: true }
330
+ }
795
331
 
796
- case 'think': {
797
- const thinkPlugin = this._framework.pluginManager && this._framework.pluginManager.get('think')
798
- if (!thinkPlugin) return { success: false, error: 'Think plugin not available' }
799
- return thinkPlugin._triggerThinking({
800
- topic: action.topic || 'Ambient agent reflection',
801
- mode: action.mode || 'reflect',
802
- depth: action.depth || 2
803
- })
332
+ checkLoopDetection(goal, actionId) {
333
+ // 如果同一操作连续重复3次,则目标失败
334
+ if (goal.lastActionId === actionId) {
335
+ goal.consecutiveSameActions++
336
+ if (goal.consecutiveSameActions >= 3) {
337
+ this._goalManager.failGoal(goal.id, '检测到循环:同一操作连续重复3次')
338
+ return true
804
339
  }
805
-
806
- case 'wait':
807
- // 显式等待
808
- await new Promise(resolve => setTimeout(resolve, action.waitMs || 5000))
809
- return { success: true, waited: action.waitMs || 5000 }
810
-
811
- case 'create_subgoal':
812
- // 由 ExplorerLoop 处理,此处仅返回标记
813
- return { success: true, isSubGoalRequest: true, subGoal: action.subGoal }
814
-
815
- default:
816
- return { success: false, error: `Unknown action type: ${action.type}` }
340
+ } else {
341
+ goal.consecutiveSameActions = 1
342
+ goal.lastActionId = actionId
817
343
  }
818
- }
819
-
820
- _getAgent() {
821
- if (this._framework._mainAgent) return this._framework._mainAgent
822
- const agents = this._framework._agents || []
823
- return agents.length > 0 ? agents[agents.length - 1] : null
344
+ return false
824
345
  }
825
346
  }
826
347
 
827
- // ─────────────────────────────────────────────────────────────────────────────
828
- // EventWatcher 同原版,增加优先级权重传递
829
- // ─────────────────────────────────────────────────────────────────────────────
830
-
831
- class EventWatcher {
832
- constructor(goalManager, framework) {
348
+ // ============================================================================
349
+ // ExplorerLoop - 主自主循环,决定并执行操作
350
+ // ============================================================================
351
+ class ExplorerLoop {
352
+ constructor(goalManager, reflector, framework, config) {
833
353
  this._goalManager = goalManager
834
- this._framework = framework
835
- this._handlers = []
836
- this._watchedEvents = [
837
- 'tool:result', 'scheduler:reminder', 'agent:message',
838
- 'think:thought_completed', 'scheduler:task_completed',
839
- 'scheduler:task_failed', 'email:received', 'webhook:received'
840
- ]
354
+ this._reflector = reflector
355
+ this._framework = framework
356
+ this._config = config
357
+ this._running = false
358
+ this._timer = null
359
+ this._lastActionTime = 0
360
+ this._tickCount = 0
361
+ this._recentActivities = []
841
362
  }
842
363
 
843
364
  start() {
844
- for (const type of this._watchedEvents) {
845
- this._handlers.push(
846
- this._framework.on(type, (data) => this._handle(type, data))
847
- )
848
- }
365
+ if (this._running) return
366
+ this._running = true
367
+ this._scheduleNext()
849
368
  }
850
369
 
851
370
  stop() {
852
- for (const h of this._handlers) h()
853
- this._handlers = []
371
+ this._running = false
372
+ if (this._timer) {
373
+ clearTimeout(this._timer)
374
+ this._timer = null
375
+ }
854
376
  }
855
377
 
856
- _handle(type, data) {
857
- const all = [
858
- ...this._goalManager.getActiveGoals(),
859
- ...this._goalManager.getPendingGoals()
860
- ]
861
- for (const goal of all) {
862
- if (this._isRelevant(goal, type, data)) {
863
- if (goal.state === GoalState.PENDING) this._goalManager.activateGoal(goal.id)
864
- this._goalManager.addEventToGoal(goal.id, { type, data })
865
- }
378
+ pause() {
379
+ this._running = false
380
+ if (this._timer) {
381
+ clearTimeout(this._timer)
382
+ this._timer = null
866
383
  }
867
384
  }
868
385
 
869
- _isRelevant(goal, eventType, data) {
870
- const conds = goal.conditions || {}
871
- if (conds.events) {
872
- const allowed = Array.isArray(conds.events) ? conds.events : [conds.events]
873
- if (!allowed.includes(eventType)) return false
386
+ resume() {
387
+ if (!this._running) {
388
+ this._running = true
389
+ this._scheduleNext()
874
390
  }
875
- if (conds.toolNames && data && data.toolName) {
876
- const names = Array.isArray(conds.toolNames) ? conds.toolNames : [conds.toolNames]
877
- if (!names.includes(data.toolName)) return false
878
- }
879
- return true
880
391
  }
881
- }
882
392
 
883
- // ─────────────────────────────────────────────────────────────────────────────
884
- // ExplorerLoop v2 — 集成 DecisionEngine 的主循环
885
- // ─────────────────────────────────────────────────────────────────────────────
886
-
887
- class ExplorerLoop {
888
- constructor(goalManager, decisionEngine, reflector, executor, scheduler, memory, config) {
889
- this._goalManager = goalManager
890
- this._decisionEngine = decisionEngine
891
- this._reflector = reflector
892
- this._executor = executor
893
- this._scheduler = scheduler
894
- this._memory = memory
895
- this._config = config
896
- this._running = false
897
- this._timer = null
898
- this._tickCount = 0
899
- this._recentActivities = []
900
- this._backoffMap = new Map() // goalId → 退避到期时间
393
+ isRunning() {
394
+ return this._running
901
395
  }
902
396
 
903
- start() { if (!this._running) { this._running = true; this._scheduleNext() } }
904
- stop() { this._running = false; if (this._timer) { clearTimeout(this._timer); this._timer = null } }
905
- pause() { this.stop() }
906
- resume() { this.start() }
907
- isRunning() { return this._running }
908
-
909
397
  getStatus() {
910
398
  return {
911
- running: this._running,
912
- tickCount: this._tickCount,
913
- activeGoals: this._goalManager.getActiveGoals().length,
914
- pendingGoals: this._goalManager.getPendingGoals().length,
915
- recentActivities: this._recentActivities.slice(-10)
399
+ running: this._running,
400
+ tickCount: this._tickCount,
401
+ lastTick: this._lastActionTime ? new Date(this._lastActionTime) : null,
402
+ recentActivities: this._recentActivities.slice(-10),
403
+ activeGoals: this._goalManager.getActiveGoals().length,
404
+ pendingGoals: this._goalManager.getPendingGoals().length
916
405
  }
917
406
  }
918
407
 
@@ -923,435 +412,731 @@ class ExplorerLoop {
923
412
 
924
413
  async _tick() {
925
414
  if (!this._running) return
926
- this._tickCount++
927
415
 
416
+ // 如果处于嵌套执行上下文中,跳过此tick
928
417
  try {
929
- // 自动激活无条件的 pending 目标
930
- for (const g of this._goalManager.getPendingGoals()) {
931
- if (!g.conditions || Object.keys(g.conditions).length === 0) {
932
- this._goalManager.activateGoal(g.id)
933
- this._log('goal_activated', { goalId: g.id, title: g.title })
418
+ if (this._framework.getExecutionContext) {
419
+ const ctx = this._framework.getExecutionContext()
420
+ if (ctx && ctx.id) {
421
+ // 跳过此tick,重新调度
422
+ this._scheduleNext()
423
+ return
934
424
  }
935
425
  }
426
+ } catch (e) {
427
+ // getExecutionContext可能不存在,继续执行
428
+ }
936
429
 
937
- // 调度:按优先级排序活跃目标
938
- const activeGoals = this._scheduler.schedule(this._goalManager.getActiveGoals())
939
-
940
- for (const goal of activeGoals) {
941
- // 退避检查
942
- const backoffUntil = this._backoffMap.get(goal.id)
943
- if (backoffUntil && Date.now() < backoffUntil) continue
430
+ this._tickCount++
431
+
944
432
 
945
- await this._processGoal(goal)
946
- }
433
+ try {
434
+ await this._processGoals()
947
435
  } catch (err) {
948
- console.error('[Ambient] Tick error:', err.message)
949
- this._log('tick_error', { message: err.message })
436
+ console.error('[Ambient] Tick错误:', err.message)
437
+ this._addActivity('error', { message: err.message })
950
438
  }
951
-
439
+ this._lastActionTime = Date.now()
440
+ // 调度下一次tick
952
441
  this._scheduleNext()
953
442
  }
954
443
 
955
- async _processGoal(goal) {
956
- const isEventDriven = goal.conditions && goal.conditions.events && goal.conditions.events.length > 0
957
- const hasEvents = (goal.eventsReceived || []).length > 0
444
+ async _processGoals() {
445
+ const activeGoals = this._goalManager.getActiveGoals()
958
446
 
959
- // 事件驱动目标:无待处理事件则跳过
960
- if (isEventDriven && !hasEvents) return
447
+ for (const goal of activeGoals) {
448
+ // 检查冷却时间
449
+ if (Date.now() - this._lastActionTime < this._config.cooldownPeriod) {
450
+ continue
451
+ }
961
452
 
962
- // ── 1. DecisionEngine 决策 ──
963
- let decision
964
- try {
965
- decision = await this._decisionEngine.decide(goal)
966
- } catch (err) {
967
- this._log('decision_error', { goalId: goal.id, error: err.message })
968
- return
969
- }
453
+ // 检查目标是否有未处理的事件
454
+ const hasNewEvents = goal.eventsReceived && goal.eventsReceived.length > 0
970
455
 
971
- if (!decision) return
456
+ // 获取下一个操作
457
+ if (goal.actions && goal.actions.length > 0) {
458
+ const action = goal.actions[0] // 简单策略:取第一个操作
972
459
 
973
- // ── 2. 处理决策结果 ──
974
- if (decision.shouldComplete) {
975
- this._goalManager.completeGoal(goal.id)
976
- this._memory.store(`目标完成: ${goal.title}`, { goalId: goal.id, tags: ['completed'] })
977
- this._log('goal_completed', { goalId: goal.id, title: goal.title })
978
- return
979
- }
460
+ // 循环检测(仅用于非事件驱动的操作)
461
+ if (!hasNewEvents && this._reflector.checkLoopDetection(goal, action.id)) {
462
+ this._addActivity('goal_failed', { goalId: goal.id, reason: '检测到循环' })
463
+ // 通知用户目标失败
464
+ this._notifyUser('目标失败', `目标 "${goal.title}" 失败:检测到循环(同一操作连续重复)`, 'error')
465
+ continue
466
+ }
980
467
 
981
- if (decision.shouldFail) {
982
- this._goalManager.failGoal(goal.id, decision.failReason || 'LLM decided to fail')
983
- this._log('goal_failed', { goalId: goal.id, reason: decision.failReason })
984
- return
985
- }
468
+ // 执行操作
469
+ const result = await this._executeAction(action, hasNewEvents ? goal.eventsReceived[0] : null)
470
+
471
+ // 评估结果
472
+ const outcome = this._reflector.evaluateOutcome(goal, result)
473
+
474
+ if (outcome.goalComplete) {
475
+ this._goalManager.completeGoal(goal.id)
476
+ this._addActivity('goal_completed', { goalId: goal.id, attempts: goal.attempts })
477
+ // 通知用户目标完成
478
+ this._notifyUser('目标完成', `目标 "${goal.title}" 已完成(尝试次数:${goal.attempts})`, 'success')
479
+ } else if (!outcome.shouldContinue) {
480
+ this._goalManager.failGoal(goal.id, '达到最大尝试次数')
481
+ this._addActivity('goal_failed', { goalId: goal.id, reason: '达到最大尝试次数' })
482
+ // 通知用户目标失败
483
+ this._notifyUser('目标失败', `目标 "${goal.title}" 失败:达到最大尝试次数`, 'error')
484
+ } else if (outcome.actionTaken) {
485
+ // 从队列中移除已完成的操作
486
+ goal.actions.shift()
487
+ this._addActivity('action_executed', { goalId: goal.id, action: action.id, hasEvents: hasNewEvents })
488
+ }
986
489
 
987
- const action = decision.action
988
- if (!action || action.type === 'wait') {
989
- this._log('action_wait', { goalId: goal.id, reasoning: decision.reasoning })
990
- this._clearEvents(goal)
991
- return
490
+ // 执行操作后清除已处理的事件
491
+ if (hasNewEvents && outcome.actionTaken) {
492
+ goal.eventsReceived = []
493
+ this._goalManager.updateGoal(goal.id, { eventsReceived: [] })
494
+ }
495
+ }
992
496
  }
993
497
 
994
- // ── 3. 子目标分解 ──
995
- if (action.type === 'create_subgoal' && action.subGoal) {
996
- const subGoal = this._goalManager.createGoal(action.subGoal, goal.id)
997
- this._goalManager.activateGoal(subGoal.id)
998
- this._log('subgoal_created', { parentId: goal.id, subGoalId: subGoal.id, title: subGoal.title })
999
- this._clearEvents(goal)
1000
- return
498
+ // 激活满足条件的待处理目标
499
+ const pendingGoals = this._goalManager.getPendingGoals()
500
+ for (const goal of pendingGoals) {
501
+ // 自动激活没有条件或条件已满足的目标
502
+ if (!goal.conditions || Object.keys(goal.conditions).length === 0) {
503
+ this._goalManager.activateGoal(goal.id)
504
+ this._addActivity('goal_activated', { goalId: goal.id })
505
+ }
1001
506
  }
507
+ }
1002
508
 
1003
- // ── 4. 执行行动 ──
1004
- const eventData = hasEvents ? goal.eventsReceived[0] : null
1005
- this._log('action_start', { goalId: goal.id, type: action.type, name: action.name })
1006
-
1007
- const result = await this._executor.execute(action, eventData)
1008
- const outcome = this._reflector.evaluate(goal, result, decision)
1009
-
1010
- // ── 5. 处理评估结果 ──
1011
- switch (outcome.status) {
1012
- case 'fail':
1013
- this._goalManager.failGoal(goal.id, outcome.reason, outcome.type)
1014
- this._log('goal_failed', { goalId: goal.id, reason: outcome.reason })
1015
- break
1016
-
1017
- case 'retry':
1018
- this._backoffMap.set(goal.id, Date.now() + (outcome.backoffMs || 5000))
1019
- this._log('action_backoff', { goalId: goal.id, backoffMs: outcome.backoffMs })
1020
- break
509
+ async _executeAction(action, eventData = null) {
510
+ if (!this._framework) {
511
+ return { success: false, error: '框架不可用' }
512
+ }
1021
513
 
1022
- case 'continue':
1023
- default:
1024
- this._log('action_done', {
1025
- goalId: goal.id,
1026
- succeeded: outcome.actionSucceeded,
1027
- type: action.type
1028
- })
1029
- // 事件驱动目标:执行后重置(继续等待下次事件)
1030
- if (isEventDriven) {
1031
- this._goalManager.updateGoal(goal.id, { attempts: 0 })
514
+ try {
515
+ if (action.type === 'tool') {
516
+ // 使用 getTools() 返回数组,按名称查找
517
+ const tools = this._framework.getTools()
518
+ const tool = tools.find(t => t.name === action.name)
519
+ if (!tool) {
520
+ return { success: false, error: `未找到工具: ${action.name}` }
1032
521
  }
1033
- break
522
+ // 如果有事件数据,合并到参数中
523
+ const args = { ...action.args }
524
+ if (eventData) {
525
+ args._event = eventData
526
+ }
527
+ const result = await tool.execute(args, this._framework)
528
+ return result
529
+ } else if (action.type === 'message') {
530
+ const agent = this._getActiveAgent()
531
+ if (!agent) {
532
+ return { success: false, error: '没有可用的代理' }
533
+ }
534
+ // 如果有事件上下文,将其包含在消息中
535
+ let content = action.content
536
+ if (eventData) {
537
+ content = `${action.content}\n\n[事件上下文: ${JSON.stringify(eventData)}]`
538
+ }
539
+ const result = await agent.pushMessage(content)
540
+ return { success: true, result }
541
+ } else if (action.type === 'think') {
542
+ // 触发思考
543
+ const thinkPlugin = this._framework.pluginManager.get('think')
544
+ if (thinkPlugin) {
545
+ // 如果有事件上下文,将其包含在主题中
546
+ let topic = action.topic || 'Ambient代理反思'
547
+ if (eventData) {
548
+ topic = `${topic}\n\n[事件上下文: ${JSON.stringify(eventData)}]`
549
+ }
550
+ const result = await thinkPlugin._triggerThinking({
551
+ topic,
552
+ mode: action.mode || 'reflect',
553
+ depth: action.depth || 2
554
+ })
555
+ return result
556
+ }
557
+ return { success: false, error: '思考插件不可用' }
558
+ }
559
+
560
+ return { success: false, error: `未知的操作类型: ${action.type}` }
561
+ } catch (err) {
562
+ return { success: false, error: err.message }
1034
563
  }
564
+ }
1035
565
 
1036
- this._clearEvents(goal)
566
+ _getActiveAgent() {
567
+ if (this._framework._mainAgent) {
568
+ return this._framework._mainAgent
569
+ }
570
+ const agents = this._framework._agents || []
571
+ return agents.length > 0 ? agents[agents.length - 1] : null
1037
572
  }
1038
573
 
1039
- _clearEvents(goal) {
1040
- if ((goal.eventsReceived || []).length > 0) {
1041
- this._goalManager.updateGoal(goal.id, { eventsReceived: [] })
574
+ _addActivity(type, data) {
575
+ this._recentActivities.push({
576
+ type,
577
+ data,
578
+ timestamp: new Date()
579
+ })
580
+ // 只保留最近50条活动记录
581
+ if (this._recentActivities.length > 50) {
582
+ this._recentActivities = this._recentActivities.slice(-50)
1042
583
  }
1043
584
  }
1044
585
 
1045
- _log(type, data) {
1046
- const entry = { type, data, ts: Date.now() }
1047
- this._recentActivities.push(entry)
1048
- if (this._recentActivities.length > 50) this._recentActivities = this._recentActivities.slice(-50)
586
+ /**
587
+ * 通知用户(通过事件发送给消息插件)
588
+ */
589
+ _notifyUser(title, message, level = 'info') {
590
+ if (!this._framework) return
591
+
592
+ // 获取目标相关的sessionId(如果有)
593
+ let sessionId = null
594
+ const sessionPlugin = this._framework.pluginManager.get('session')
595
+ if (sessionPlugin) {
596
+ const sessions = sessionPlugin.listSessions()
597
+ if (sessions.length > 0) {
598
+ // 取最新的会话
599
+ sessions.sort((a, b) => new Date(b.lastActive).getTime() - new Date(a.lastActive).getTime())
600
+ sessionId = sessions[0].id
601
+ }
602
+ }
603
+
604
+ // 发送统一的通知事件
605
+ this._framework.emit('notification', {
606
+ title,
607
+ message,
608
+ source: 'ambient',
609
+ level, // 'info' | 'warning' | 'success' | 'error'
610
+ sessionId,
611
+ timestamp: new Date()
612
+ })
613
+
614
+ console.log(`[Ambient:通知] ${title}: ${message}`)
1049
615
  }
1050
616
  }
1051
617
 
1052
- // ─────────────────────────────────────────────────────────────────────────────
1053
- // AmbientAgentPlugin v2 — 主插件类
1054
- // ─────────────────────────────────────────────────────────────────────────────
1055
-
618
+ // ============================================================================
619
+ // 主插件类
620
+ // ============================================================================
1056
621
  class AmbientAgentPlugin extends Plugin {
1057
622
  constructor(config = {}) {
1058
623
  super()
1059
- this.name = 'ambient'
1060
- this.version = '2.0.0'
1061
- this.description = 'Ambient Agent v2 — 自主执行引擎(LLM 推理 + 优先级调度)'
1062
- this.priority = 18
1063
- this.system = true
624
+ this.name = 'ambient'
625
+ this.version = '1.0.0'
626
+ this.description = 'Ambient Agent - 持续后台运行的智能代理,用于主动监控和执行操作'
627
+ this.priority = 18
628
+ this.system = true
1064
629
 
1065
630
  this.config = {
1066
- enabled: config.enabled !== false,
1067
- tickInterval: config.tickInterval || 5000,
1068
- cooldownPeriod: config.cooldownPeriod || 3000,
631
+ enabled: config.enabled !== false,
632
+ tickInterval: config.tickInterval || 5000, // tick间隔(毫秒)
633
+ cooldownPeriod: config.cooldownPeriod || 3000, // 冷却时间(毫秒)
1069
634
  persistencePath: config.persistencePath || '.agent/data/ambient',
1070
- defaultGoals: config.defaultGoals || [],
1071
- llmCallTimeout: config.llmCallTimeout || 30000,
1072
- actionTimeout: config.actionTimeout || 20000
635
+ defaultGoals: config.defaultGoals || []
1073
636
  }
1074
637
 
1075
- this._framework = null
1076
- this._stateStore = null
1077
- this._goalManager = null
1078
- this._memory = null
1079
- this._contextBuilder = null
1080
- this._decisionEngine = null
1081
- this._reflector = null
1082
- this._executor = null
1083
- this._scheduler = null
1084
- this._eventWatcher = null
1085
- this._explorerLoop = null
638
+ this._framework = null
639
+ this._stateStore = null
640
+ this._goalManager = null
641
+ this._eventWatcher = null
642
+ this._reflector = null
643
+ this._explorerLoop = null
644
+ this._memories = []
1086
645
  }
1087
646
 
1088
647
  install(framework) {
1089
- this._framework = framework
1090
- this._stateStore = new StateStore(this.config.persistencePath)
1091
- this._goalManager = new GoalManager(this._stateStore)
1092
- this._memory = new SemanticMemory(this._stateStore)
1093
- this._contextBuilder = new ContextBuilder(this._memory, this._goalManager)
1094
- this._reflector = new Reflector(this._goalManager, this._memory, this._stateStore)
1095
- this._executor = new ActionExecutor(framework, this.config)
1096
- this._scheduler = new PriorityScheduler()
648
+ this._framework = framework
649
+ this._stateStore = new StateStore(this.config.persistencePath)
650
+ this._goalManager = new GoalManager(this._stateStore)
651
+ this._reflector = new Reflector(this._goalManager)
652
+
653
+ // 加载持久化的记忆
654
+ this._memories = this._stateStore.loadMemories()
655
+
1097
656
  return this
1098
657
  }
1099
658
 
1100
659
  start(framework) {
1101
- if (!this.config.enabled) return this
1102
-
1103
- // 创建专用的子 Agent 用于 ambient 决策(不干扰主 Agent)
1104
- this._ambientAgent = framework.createAgent({
1105
- name: 'ambient-decision',
1106
- systemPrompt: '你是一个任务决策助手。根据目标和当前状态,返回最优行动决策(JSON格式)。',
1107
- model: framework._mainAgent?.model || 'deepseek-chat',
1108
- apiKey: framework._mainAgent?.apiKey,
1109
- provider: framework._mainAgent?.provider,
1110
- baseURL: framework._mainAgent?.baseURL
1111
- })
1112
-
1113
- this._decisionEngine = new DecisionEngine(framework, this._contextBuilder, this._goalManager, this._stateStore, this.config, this._ambientAgent)
660
+ if (!this.config.enabled) {
661
+ console.log('[Ambient] 插件已禁用,跳过启动')
662
+ return this
663
+ }
1114
664
 
665
+ // 如果没有现有目标,创建默认目标
1115
666
  if (this._goalManager.getAllGoals().length === 0 && this.config.defaultGoals.length > 0) {
1116
- for (const g of this.config.defaultGoals) this._goalManager.createGoal(g)
667
+ for (const goalDef of this.config.defaultGoals) {
668
+ this._goalManager.createGoal(goalDef)
669
+ }
1117
670
  }
1118
671
 
672
+ // 启动事件监听器
1119
673
  this._eventWatcher = new EventWatcher(this._goalManager, this._framework)
1120
674
  this._eventWatcher.start()
1121
675
 
1122
- this._explorerLoop = new ExplorerLoop(
1123
- this._goalManager,
1124
- this._decisionEngine,
1125
- this._reflector,
1126
- this._executor,
1127
- this._scheduler,
1128
- this._memory,
1129
- { tickInterval: this.config.tickInterval }
1130
- )
676
+ // 动态更新description显示支持的事件
677
+ const events = Array.from(this._eventWatcher._relevantEvents).join(', ')
678
+ this.description = `Ambient Agent - 持续后台运行的智能代理,用于主动监控和执行操作
679
+ 支持的事件:${events}`
680
+
681
+ // 启动探索循环
682
+ this._explorerLoop = new ExplorerLoop(this._goalManager, this._reflector, this._framework, {
683
+ tickInterval: this.config.tickInterval,
684
+ cooldownPeriod: this.config.cooldownPeriod
685
+ })
1131
686
  this._explorerLoop.start()
1132
687
 
688
+ // 注册工具
1133
689
  this._registerTools(framework)
690
+
691
+ console.log('[Ambient] 插件已启动')
1134
692
  return this
1135
693
  }
1136
694
 
1137
695
  _registerTools(framework) {
1138
- // ── ambient_goals ──
696
+ // ambient_goals - 列出/创建/更新/删除目标
1139
697
  framework.registerTool({
1140
698
  name: 'ambient_goals',
1141
- description: '管理 Ambient Agent 目标 列出/创建/更新/删除/激活/暂停/恢复/分解子目标',
699
+ description: '管理Ambient Agent目标 - 列出、创建、更新、删除、激活目标',
1142
700
  inputSchema: z.object({
1143
- action: z.enum(['list', 'create', 'update', 'delete', 'activate', 'pause', 'resume', 'create_subgoal']),
1144
- goalId: z.string().optional(),
1145
- parentId: z.string().optional().describe('父目标 ID(create_subgoal 时使用)'),
1146
- title: z.string().optional(),
1147
- description: z.string().optional(),
1148
- priority: z.number().optional(),
1149
- successCriteria: z.string().optional().describe('明确的成功标准,供 LLM 判断完成'),
1150
- actions: z.array(z.any()).optional().describe('行动提示(LLM 参考,非强制)'),
1151
- conditions: z.object({
1152
- events: z.union([z.string(), z.array(z.string())]).optional(),
1153
- toolNames: z.union([z.string(), z.array(z.string())]).optional()
1154
- }).optional(),
1155
- maxAttempts: z.number().optional()
701
+ action: z.enum(['list', 'create', 'update', 'delete', 'activate']).describe('执行的操作'),
702
+ goalId: z.string().optional().describe('目标ID(更新/删除/激活时必需)'),
703
+ title: z.string().optional().describe('目标标题(创建/更新时使用)'),
704
+ description: z.string().optional().describe('目标描述(创建/更新时使用)'),
705
+ priority: z.number().optional().describe('优先级1-10,数值越高越重要(创建/更新时使用)'),
706
+ actions: z.array(z.object({
707
+ id: z.string().optional().describe('操作标识符'),
708
+ type: z.enum(['tool', 'message', 'think']).describe('操作类型'),
709
+ name: z.string().optional().describe('工具名称(tool类型时使用)'),
710
+ args: z.record(z.any()).optional().describe('工具参数(tool类型时使用)'),
711
+ content: z.string().optional().describe('消息内容(message类型时使用)'),
712
+ topic: z.string().optional().describe('思考主题(think类型时使用)'),
713
+ mode: z.enum(['reflect', 'brainstorm', 'analyze', 'plan']).optional().describe('思考模式(think类型时使用)')
714
+ })).optional().describe('要执行的操作列表(创建/更新时使用)'),
715
+ conditions: z.object({
716
+ events: z.union([z.string(), z.array(z.string())]).optional().describe('要监听的事件类型'),
717
+ toolNames: z.union([z.string(), z.array(z.string())]).optional().describe('按工具名称过滤')
718
+ }).optional().describe('激活条件(创建/更新时使用)')
1156
719
  }),
1157
- execute: async (args) => this._handleGoalsTool(args)
720
+ execute: async (args) => {
721
+ return this._handleGoalsTool(args)
722
+ }
1158
723
  })
1159
724
 
1160
- // ── ambient_status ──
725
+ // ambient_status - 获取当前循环状态
1161
726
  framework.registerTool({
1162
727
  name: 'ambient_status',
1163
- description: '获取 Ambient Agent 运行状态 — 循环状态/活跃目标/最近活动/执行日志',
728
+ description: '获取当前Ambient Agent状态 - 循环状态、进行中的目标、最近活动',
729
+ inputSchema: z.object({}),
730
+ execute: async () => {
731
+ return this._handleStatusTool()
732
+ }
733
+ })
734
+
735
+ // ambient_think - 触发主动LLM思考
736
+ framework.registerTool({
737
+ name: 'ambient_think',
738
+ description: '为某个目标触发主动LLM思考 - 模式:reflect(反思)、brainstorm(头脑风暴)、plan(计划)、analyze(分析)',
1164
739
  inputSchema: z.object({
1165
- includeLog: z.boolean().optional().describe('是否包含执行日志(最近 20 条)')
740
+ goalId: z.string().optional().describe('要思考的目标ID'),
741
+ mode: z.enum(['reflect', 'brainstorm', 'plan', 'analyze']).describe('思考模式'),
742
+ topic: z.string().optional().describe('要思考的主题'),
743
+ depth: z.number().optional().describe('思考深度1-5')
1166
744
  }),
1167
- execute: async (args) => this._handleStatusTool(args)
745
+ execute: async (args) => {
746
+ return this._handleThinkTool(args)
747
+ }
1168
748
  })
1169
749
 
1170
- // ── ambient_remember ──
750
+ // ambient_remember - 存储/检索/搜索持久化记忆
1171
751
  framework.registerTool({
1172
752
  name: 'ambient_remember',
1173
- description: '操作 Ambient Agent 语义记忆 — 存储/检索/搜索',
753
+ description: 'Ambient Agent存储或检索持久化记忆',
1174
754
  inputSchema: z.object({
1175
- action: z.enum(['store', 'retrieve', 'search']),
1176
- content: z.string().optional(),
1177
- key: z.string().optional(),
1178
- tags: z.array(z.string()).optional(),
1179
- scope: z.enum(['long', 'working', 'all']).optional(),
1180
- goalId: z.string().optional(),
1181
- query: z.string().optional(),
1182
- limit: z.number().optional()
755
+ action: z.enum(['store', 'retrieve', 'search']).describe('操作:store存储记忆、retrieve检索最近、search搜索'),
756
+ content: z.string().optional().describe('记忆内容(store时使用)'),
757
+ key: z.string().optional().describe('记忆键(store/retrieve时使用)'),
758
+ query: z.string().optional().describe('搜索查询(search时使用)'),
759
+ limit: z.number().optional().describe('最大结果数(retrieve/search时使用)')
1183
760
  }),
1184
- execute: async (args) => this._handleRememberTool(args)
761
+ execute: async (args) => {
762
+ return this._handleRememberTool(args)
763
+ }
1185
764
  })
1186
765
 
1187
- // ── ambient_control ──
766
+ // ambient_control - 暂停/恢复/调整探索循环
1188
767
  framework.registerTool({
1189
768
  name: 'ambient_control',
1190
- description: '控制 Ambient Agent 暂停/恢复/调整参数',
769
+ description: '控制Ambient Agent探索循环 - 暂停、恢复或调整设置',
1191
770
  inputSchema: z.object({
1192
- action: z.enum(['pause', 'resume', 'status', 'adjust', 'clear_log']),
1193
- tickInterval: z.number().optional(),
1194
- cooldownPeriod: z.number().optional(),
1195
- llmCallTimeout: z.number().optional()
771
+ action: z.enum(['pause', 'resume', 'status', 'adjust']).describe('控制操作'),
772
+ tickInterval: z.number().optional().describe('新的tick间隔毫秒数(adjust时使用)'),
773
+ cooldownPeriod: z.number().optional().describe('新的冷却时间毫秒数(adjust时使用)')
1196
774
  }),
1197
- execute: async (args) => this._handleControlTool(args)
775
+ execute: async (args) => {
776
+ return this._handleControlTool(args)
777
+ }
1198
778
  })
1199
779
  }
1200
780
 
1201
781
  _handleGoalsTool(args) {
1202
- const { action, goalId, parentId, title, description, priority,
1203
- successCriteria, actions, conditions, maxAttempts } = args
782
+ const { action, goalId, title, description, priority, actions, conditions } = args
1204
783
 
1205
784
  switch (action) {
1206
785
  case 'list': {
1207
- const all = this._goalManager.getAllGoals()
786
+ const allGoals = this._goalManager.getAllGoals()
1208
787
  return {
1209
788
  success: true,
1210
- goals: all.map(g => ({
1211
- id: g.id, title: g.title, state: g.state,
1212
- priority: g.priority, attempts: g.attempts,
1213
- parentId: g.parentId, subGoalCount: (g.subGoalIds || []).length,
1214
- eventsQueued: (g.eventsReceived || []).length,
1215
- lastDecisionAt: g.lastDecisionAt
789
+ goals: allGoals.map(g => ({
790
+ id: g.id,
791
+ title: g.title,
792
+ state: g.state,
793
+ priority: g.priority,
794
+ actionsCount: g.actions ? g.actions.length : 0,
795
+ attempts: g.attempts,
796
+ createdAt: g.createdAt,
797
+ activatedAt: g.activatedAt,
798
+ completedAt: g.completedAt,
799
+ failedAt: g.failedAt
1216
800
  })),
1217
- stats: {
1218
- total: all.length,
1219
- active: all.filter(g => g.state === GoalState.ACTIVE).length,
1220
- pending: all.filter(g => g.state === GoalState.PENDING).length,
1221
- completed: all.filter(g => g.state === GoalState.COMPLETED).length,
1222
- failed: all.filter(g => g.state === GoalState.FAILED).length
1223
- }
801
+ total: allGoals.length,
802
+ active: this._goalManager.getActiveGoals().length,
803
+ pending: this._goalManager.getPendingGoals().length
1224
804
  }
1225
805
  }
806
+
1226
807
  case 'create': {
1227
- if (!title) return { success: false, error: 'title is required' }
1228
- const goal = this._goalManager.createGoal({ title, description, priority, actions, conditions, maxAttempts, successCriteria })
808
+ if (!title) {
809
+ return { success: false, error: '创建目标需要提供标题' }
810
+ }
811
+ const goal = this._goalManager.createGoal({ title, description, priority, actions, conditions })
1229
812
  return { success: true, goal }
1230
813
  }
1231
- case 'create_subgoal': {
1232
- if (!parentId) return { success: false, error: 'parentId is required' }
1233
- if (!title) return { success: false, error: 'title is required' }
1234
- const sub = this._goalManager.createGoal({ title, description, priority, actions, conditions, maxAttempts, successCriteria }, parentId)
1235
- return { success: true, goal: sub }
1236
- }
814
+
1237
815
  case 'update': {
1238
- if (!goalId) return { success: false, error: 'goalId is required' }
816
+ if (!goalId) {
817
+ return { success: false, error: '更新目标需要提供目标ID' }
818
+ }
1239
819
  const updates = {}
1240
- if (title !== undefined) updates.title = title
1241
- if (description !== undefined) updates.description = description
1242
- if (priority !== undefined) updates.priority = priority
1243
- if (actions !== undefined) updates.actionHints = actions
1244
- if (conditions !== undefined) updates.conditions = conditions
1245
- if (successCriteria !== undefined) updates.successCriteria = successCriteria
1246
- if (maxAttempts !== undefined) updates.maxAttempts = maxAttempts
1247
- const g = this._goalManager.updateGoal(goalId, updates)
1248
- return g ? { success: true, goal: g } : { success: false, error: 'Goal not found' }
820
+ if (title !== undefined) updates.title = title
821
+ if (description !== undefined) updates.description = description
822
+ if (priority !== undefined) updates.priority = priority
823
+ if (actions !== undefined) updates.actions = actions
824
+ if (conditions !== undefined) updates.conditions = conditions
825
+ const goal = this._goalManager.updateGoal(goalId, updates)
826
+ return goal ? { success: true, goal } : { success: false, error: '目标未找到' }
827
+ }
828
+
829
+ case 'delete': {
830
+ if (!goalId) {
831
+ return { success: false, error: '删除目标需要提供目标ID' }
832
+ }
833
+ const deleted = this._goalManager.deleteGoal(goalId)
834
+ return { success: deleted }
835
+ }
836
+
837
+ case 'activate': {
838
+ if (!goalId) {
839
+ return { success: false, error: '激活目标需要提供目标ID' }
840
+ }
841
+ const goal = this._goalManager.activateGoal(goalId)
842
+ return goal ? { success: true, goal } : { success: false, error: '目标未找到或不是待激活状态' }
1249
843
  }
1250
- case 'delete': { if (!goalId) return { success: false, error: 'goalId required' }; return { success: this._goalManager.deleteGoal(goalId) } }
1251
- case 'activate': { if (!goalId) return { success: false, error: 'goalId required' }; const g = this._goalManager.activateGoal(goalId); return g ? { success: true, goal: g } : { success: false, error: 'Not found or not pending' } }
1252
- case 'pause': { if (!goalId) return { success: false, error: 'goalId required' }; const g = this._goalManager.pauseGoal(goalId); return g ? { success: true, goal: g } : { success: false, error: 'Not found or not active' } }
1253
- case 'resume': { if (!goalId) return { success: false, error: 'goalId required' }; const g = this._goalManager.resumeGoal(goalId); return g ? { success: true, goal: g } : { success: false, error: 'Not found or not paused' } }
1254
- default: return { success: false, error: `Unknown action: ${action}` }
844
+
845
+ default:
846
+ return { success: false, error: `未知操作: ${action}` }
1255
847
  }
1256
848
  }
1257
849
 
1258
- _handleStatusTool(args = {}) {
1259
- const loop = this._explorerLoop
1260
- if (!loop) return { success: false, error: 'Loop not initialized' }
850
+ _handleStatusTool() {
851
+ if (!this._explorerLoop) {
852
+ return { success: false, error: '探索循环未初始化' }
853
+ }
854
+
855
+ const loopStatus = this._explorerLoop.getStatus()
856
+ const activeGoals = this._goalManager.getActiveGoals().map(g => ({
857
+ id: g.id,
858
+ title: g.title,
859
+ priority: g.priority,
860
+ attempts: g.attempts,
861
+ lastActionId: g.lastActionId
862
+ }))
863
+ const pendingGoals = this._goalManager.getPendingGoals().map(g => ({
864
+ id: g.id,
865
+ title: g.title,
866
+ priority: g.priority
867
+ }))
1261
868
 
1262
- const status = loop.getStatus()
1263
- const result = {
869
+ return {
1264
870
  success: true,
1265
871
  loop: {
1266
- running: status.running,
1267
- tickCount: status.tickCount,
1268
- activeGoals: status.activeGoals,
1269
- pendingGoals: status.pendingGoals,
1270
- config: {
1271
- tickInterval: this.config.tickInterval,
1272
- llmCallTimeout: this.config.llmCallTimeout,
1273
- actionTimeout: this.config.actionTimeout
1274
- }
872
+ running: loopStatus.running,
873
+ tickCount: loopStatus.tickCount,
874
+ lastTick: loopStatus.lastTick,
875
+ tickInterval: this.config.tickInterval,
876
+ cooldownPeriod: this.config.cooldownPeriod
1275
877
  },
1276
- goals: {
1277
- active: this._goalManager.getActiveGoals().map(g => ({
1278
- id: g.id, title: g.title, priority: g.priority,
1279
- attempts: g.attempts, eventsQueued: (g.eventsReceived || []).length,
1280
- lastDecisionAt: g.lastDecisionAt
1281
- })),
1282
- pending: this._goalManager.getPendingGoals().map(g => ({ id: g.id, title: g.title }))
1283
- },
1284
- recentActivities: status.recentActivities
878
+ activeGoals,
879
+ pendingGoals,
880
+ recentActivities: loopStatus.recentActivities
1285
881
  }
882
+ }
883
+
884
+ async _handleThinkTool(args) {
885
+ const { goalId, mode, topic, depth } = args
1286
886
 
1287
- if (args.includeLog) {
1288
- result.executionLog = this._stateStore.loadLog().slice(-20)
887
+ // 获取活跃代理
888
+ const agent = this._getActiveAgent()
889
+ if (!agent) {
890
+ return { success: false, error: '没有可用的活跃代理' }
1289
891
  }
1290
892
 
1291
- return result
893
+ // 构建思考提示
894
+ let prompt = ''
895
+ if (goalId) {
896
+ const goal = this._goalManager.getGoal(goalId)
897
+ if (goal) {
898
+ prompt = this._buildGoalThinkPrompt(goal, mode, topic)
899
+ } else {
900
+ return { success: false, error: '目标未找到' }
901
+ }
902
+ } else {
903
+ prompt = this._buildFreeThinkPrompt(mode, topic)
904
+ }
905
+
906
+ // 如果代理忙,等待其变为可用
907
+ let attempts = 0
908
+ const maxWaitAttempts = 10
909
+ const waitInterval = 500
910
+
911
+ while (agent._status === 'busy' && attempts < maxWaitAttempts) {
912
+ console.log('[Ambient] 代理忙,等待中...')
913
+ await new Promise(resolve => setTimeout(resolve, waitInterval))
914
+ attempts++
915
+ }
916
+
917
+ if (agent._status === 'busy') {
918
+ return {
919
+ success: false,
920
+ error: '代理繁忙,无法及时变为可用。请稍后重试。',
921
+ queued: true
922
+ }
923
+ }
924
+
925
+ // 通过代理执行思考
926
+ const thinkPlugin = this._framework.pluginManager.get('think')
927
+ if (thinkPlugin) {
928
+ const result = await thinkPlugin._triggerThinking({ topic: prompt, mode, depth: depth || 2 })
929
+ // 如果结果提示繁忙,返回更友好的消息
930
+ if (result && result.message && result.message.includes && result.message.includes('busy')) {
931
+ return {
932
+ success: true,
933
+ queued: true,
934
+ message: '思考请求已排队,将在代理空闲时处理。'
935
+ }
936
+ }
937
+ return result
938
+ }
939
+
940
+ // 备用:直接推送消息
941
+ return agent.pushMessage(prompt).then(result => ({
942
+ success: true,
943
+ result: typeof result === 'string' ? result : JSON.stringify(result)
944
+ })).catch(err => ({
945
+ success: false,
946
+ error: err.message
947
+ }))
948
+ }
949
+
950
+ _buildGoalThinkPrompt(goal, mode, topic) {
951
+ const modePrompts = {
952
+ reflect: `作为Ambient Agent,反思当前目标:
953
+ 标题: ${goal.title}
954
+ 描述: ${goal.description || '无'}
955
+ 优先级: ${goal.priority}
956
+ 状态: ${goal.state}
957
+ 尝试次数: ${goal.attempts}
958
+
959
+ ${topic ? `额外关注点: ${topic}` : ''}
960
+
961
+ 请反思:
962
+ 1. 这个目标仍然相关且可实现吗?
963
+ 2. 操作是否适合这个目标?
964
+ 3.有什么可以改进的?`,
965
+ brainstorm: `为Ambient Agent目标头脑风暴新方法:
966
+ 标题: ${goal.title}
967
+ ${goal.description ? `描述: ${goal.description}` : ''}
968
+ 计划的操作数: ${goal.actions ? goal.actions.length : 0}
969
+
970
+ ${topic ? `关注点: ${topic}` : '生成关于如何更有效地追求这个目标的新想法。'}`,
971
+ plan: `为Ambient Agent目标制定更精细的计划:
972
+ 标题: ${goal.title}
973
+ ${goal.description ? `描述: ${goal.description}` : ''}
974
+ ${topic ? `额外上下文: ${topic}` : ''}
975
+
976
+ 制定一个清晰、可操作的计划。`,
977
+ analyze: `分析Ambient Agent目标:
978
+ 标题: ${goal.title}
979
+ 状态: ${goal.state}
980
+ 优先级: ${goal.priority}
981
+ 操作: ${goal.actions ? JSON.stringify(goal.actions) : '无'}
982
+
983
+ ${topic ? `分析重点: ${topic}` : '这个目标的优势、劣势和潜在问题是什么?'}`
984
+ }
985
+ return modePrompts[mode] || modePrompts.reflect
986
+ }
987
+
988
+ _buildFreeThinkPrompt(mode, topic) {
989
+ const modePrompts = {
990
+ reflect: `Ambient Agent反思: ${topic || '思考系统和目标的当前状态。有什么可以改进的?'}`,
991
+ brainstorm: `Ambient Agent头脑风暴: ${topic || '生成关于新目标或方法的有创意想法。'}`,
992
+ plan: `Ambient Agent计划: ${topic || '为待实现的目标制定计划。'}`,
993
+ analyze: `Ambient Agent分析: ${topic || '分析当前目标及其进展。'}`
994
+ }
995
+ return modePrompts[mode] || modePrompts.reflect
1292
996
  }
1293
997
 
1294
998
  _handleRememberTool(args) {
1295
- const { action, content, key, tags, scope, goalId, query, limit } = args
999
+ const { action, content, key, query, limit } = args
1000
+ const maxResults = limit || 10
1296
1001
 
1297
1002
  switch (action) {
1298
1003
  case 'store': {
1299
- if (!content) return { success: false, error: 'content required' }
1300
- const mem = this._memory.store(content, { key, tags, scope: scope || 'long', goalId })
1301
- return { success: true, memory: mem }
1004
+ if (!content) {
1005
+ return { success: false, error: '存储需要提供内容' }
1006
+ }
1007
+ const memoryKey = key || `memory_${Date.now()}`
1008
+ const memory = {
1009
+ key: memoryKey,
1010
+ content,
1011
+ timestamp: new Date()
1012
+ }
1013
+ this._memories.push(memory)
1014
+ this._stateStore.saveMemories(this._memories)
1015
+ return { success: true, memory }
1302
1016
  }
1017
+
1303
1018
  case 'retrieve': {
1304
- const mems = this._memory.recent(limit || 10, scope || 'all')
1305
- return { success: true, memories: mems, total: mems.length }
1019
+ const memories = this._memories.slice(-maxResults).reverse()
1020
+ return {
1021
+ success: true,
1022
+ memories,
1023
+ total: this._memories.length
1024
+ }
1306
1025
  }
1026
+
1307
1027
  case 'search': {
1308
- if (!query) return { success: false, error: 'query required' }
1309
- const results = this._memory.search(query, { limit: limit || 10, scope: scope || 'all', goalId, tags })
1310
- return { success: true, results, total: results.length }
1028
+ if (!query) {
1029
+ return { success: false, error: '搜索需要提供查询词' }
1030
+ }
1031
+ const queryLower = query.toLowerCase()
1032
+ const results = this._memories
1033
+ .filter(m => m.content.toLowerCase().includes(queryLower))
1034
+ .slice(-maxResults)
1035
+ .reverse()
1036
+ return {
1037
+ success: true,
1038
+ results,
1039
+ total: results.length
1040
+ }
1311
1041
  }
1312
- default: return { success: false, error: `Unknown action: ${action}` }
1042
+
1043
+ default:
1044
+ return { success: false, error: `未知操作: ${action}` }
1313
1045
  }
1314
1046
  }
1315
1047
 
1316
1048
  _handleControlTool(args) {
1317
- const { action, tickInterval, cooldownPeriod, llmCallTimeout } = args
1318
- const loop = this._explorerLoop
1049
+ const { action, tickInterval, cooldownPeriod } = args
1319
1050
 
1320
1051
  switch (action) {
1321
- case 'pause': { if (!loop) return { success: false }; loop.pause(); return { success: true, message: 'Paused' } }
1322
- case 'resume': { if (!loop) return { success: false }; loop.resume(); return { success: true, message: 'Resumed' } }
1323
- case 'status': return this._handleStatusTool()
1324
- case 'adjust': {
1325
- if (tickInterval) this.config.tickInterval = tickInterval
1326
- if (cooldownPeriod) this.config.cooldownPeriod = cooldownPeriod
1327
- if (llmCallTimeout) { this.config.llmCallTimeout = llmCallTimeout; this._decisionEngine._llmCallTimeout = llmCallTimeout }
1328
- return { success: true, config: this.config }
1052
+ case 'pause': {
1053
+ if (!this._explorerLoop) {
1054
+ return { success: false, error: '探索循环未初始化' }
1055
+ }
1056
+ this._explorerLoop.pause()
1057
+ return { success: true, message: '探索循环已暂停' }
1329
1058
  }
1330
- case 'clear_log': {
1331
- this._stateStore._save('execution_log', [])
1332
- return { success: true, message: 'Log cleared' }
1059
+
1060
+ case 'resume': {
1061
+ if (!this._explorerLoop) {
1062
+ return { success: false, error: '探索循环未初始化' }
1063
+ }
1064
+ this._explorerLoop.resume()
1065
+ return { success: true, message: '探索循环已恢复' }
1333
1066
  }
1334
- default: return { success: false, error: `Unknown action: ${action}` }
1067
+
1068
+ case 'status': {
1069
+ if (!this._explorerLoop) {
1070
+ return { success: false, error: '探索循环未初始化' }
1071
+ }
1072
+ const status = this._explorerLoop.getStatus()
1073
+ return {
1074
+ success: true,
1075
+ running: status.running,
1076
+ tickCount: status.tickCount,
1077
+ lastTick: status.lastTick,
1078
+ tickInterval: this.config.tickInterval,
1079
+ cooldownPeriod: this.config.cooldownPeriod
1080
+ }
1081
+ }
1082
+
1083
+ case 'adjust': {
1084
+ if (tickInterval) {
1085
+ this.config.tickInterval = tickInterval
1086
+ }
1087
+ if (cooldownPeriod) {
1088
+ this.config.cooldownPeriod = cooldownPeriod
1089
+ }
1090
+ return {
1091
+ success: true,
1092
+ message: '设置已调整',
1093
+ tickInterval: this.config.tickInterval,
1094
+ cooldownPeriod: this.config.cooldownPeriod
1095
+ }
1096
+ }
1097
+
1098
+ default:
1099
+ return { success: false, error: `未知操作: ${action}` }
1335
1100
  }
1336
1101
  }
1337
1102
 
1103
+ _getActiveAgent() {
1104
+ if (this._framework._mainAgent) {
1105
+ return this._framework._mainAgent
1106
+ }
1107
+ const agents = this._framework._agents || []
1108
+ return agents.length > 0 ? agents[agents.length - 1] : null
1109
+ }
1110
+
1338
1111
  reload(framework) {
1339
1112
  this._framework = framework
1340
- if (this._decisionEngine) this._decisionEngine._framework = framework
1341
- if (this._executor) this._executor._framework = framework
1342
- if (this._eventWatcher && this._explorerLoop && this._explorerLoop.isRunning()) {
1343
- this._eventWatcher.stop()
1344
- this._eventWatcher = new EventWatcher(this._goalManager, framework)
1113
+ if (this._explorerLoop && this._explorerLoop.isRunning()) {
1114
+ // 用新的框架引用重新启动
1115
+ this._eventWatcher = new EventWatcher(this._goalManager, this._framework)
1345
1116
  this._eventWatcher.start()
1346
1117
  }
1347
1118
  }
1348
1119
 
1349
- uninstall() {
1350
- if (this._explorerLoop) { this._explorerLoop.stop(); this._explorerLoop = null }
1351
- if (this._eventWatcher) { this._eventWatcher.stop(); this._eventWatcher = null }
1352
- this._memory && this._memory.clearWorking()
1120
+ uninstall(framework) {
1121
+ // 停止探索循环
1122
+ if (this._explorerLoop) {
1123
+ this._explorerLoop.stop()
1124
+ this._explorerLoop = null
1125
+ }
1126
+
1127
+ // 停止事件监听器
1128
+ if (this._eventWatcher) {
1129
+ this._eventWatcher.stop()
1130
+ this._eventWatcher = null
1131
+ }
1132
+
1133
+ // 清除引用
1353
1134
  this._framework = null
1135
+ this._goalManager = null
1136
+ this._reflector = null
1137
+ this._stateStore = null
1138
+ this._memories = []
1354
1139
  }
1355
1140
  }
1356
1141
 
1357
- module.exports = { AmbientAgentPlugin, GoalState, FailureType }
1142
+ module.exports = { AmbientAgentPlugin, GoalState }