foliko 1.0.62 → 1.0.63

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,195 +1,320 @@
1
1
  /**
2
- * Ambient Agent 插件
3
- * 持续后台运行的智能代理,监控事件并主动执行操作
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 — 失败分类 + 差异化恢复策略
4
10
  */
5
11
 
6
12
  const { Plugin } = require('../src/core/plugin-base')
7
13
  const { z } = require('zod')
8
14
  const fs = require('fs')
9
15
  const path = require('path')
16
+ const crypto = require('crypto')
17
+
18
+ // ─────────────────────────────────────────────────────────────────────────────
19
+ // 常量
20
+ // ─────────────────────────────────────────────────────────────────────────────
10
21
 
11
- // 目标生命周期状态
12
22
  const GoalState = {
13
- PENDING: 'pending', // 待激活
14
- ACTIVE: 'active', // 执行中
15
- COMPLETED: 'completed', // 已完成
16
- FAILED: 'failed' // 已失败
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'
17
37
  }
18
38
 
19
- // 生成唯一ID
20
39
  function generateId() {
21
- if (require('crypto').randomUUID) {
22
- return require('crypto').randomUUID()
23
- }
24
- return `goal_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
40
+ return crypto.randomUUID ? crypto.randomUUID() : `id_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`
25
41
  }
26
42
 
27
- // ============================================================================
28
- // StateStore - 持久化目标和记忆到 .agent/data/ambient/*.json
29
- // ============================================================================
43
+ // ─────────────────────────────────────────────────────────────────────────────
44
+ // StateStore 持久化(同原版,增加 executionLog)
45
+ // ─────────────────────────────────────────────────────────────────────────────
46
+
30
47
  class StateStore {
31
48
  constructor(persistencePath) {
32
- this._persistencePath = persistencePath
49
+ this._path = persistencePath
33
50
  this._ensureDir()
34
51
  }
35
52
 
36
53
  _ensureDir() {
37
- if (!fs.existsSync(this._persistencePath)) {
38
- fs.mkdirSync(this._persistencePath, { recursive: true })
39
- }
54
+ if (!fs.existsSync(this._path)) fs.mkdirSync(this._path, { recursive: true })
40
55
  }
41
56
 
42
- _getGoalsPath() {
43
- return path.join(this._persistencePath, 'goals.json')
44
- }
57
+ _file(name) { return path.join(this._path, `${name}.json`) }
45
58
 
46
- _getMemoriesPath() {
47
- return path.join(this._persistencePath, 'memories.json')
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) }
48
62
  }
49
63
 
50
- saveGoals(goals) {
64
+ _load(name, fallback) {
51
65
  try {
52
- fs.writeFileSync(this._getGoalsPath(), JSON.stringify(goals, null, 2))
53
- } catch (err) {
54
- console.error('[Ambient] 保存目标失败:', err.message)
55
- }
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
56
70
  }
57
71
 
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)
64
- }
65
- } catch (err) {
66
- console.error('[Ambient] 加载目标失败:', err.message)
67
- }
68
- return []
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))
69
81
  }
82
+ loadLog() { return this._load('execution_log', []) }
83
+ }
70
84
 
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
- }
85
+ // ─────────────────────────────────────────────────────────────────────────────
86
+ // SemanticMemory — 替代原始 memories[] 数组
87
+ // 支持:关键词索引检索 · 时间衰减评分 · 工作记忆(临时,不持久)
88
+ // ─────────────────────────────────────────────────────────────────────────────
89
+
90
+ class SemanticMemory {
91
+ constructor(stateStore) {
92
+ this._store = stateStore
93
+ this._long = stateStore.loadMemories() // 长期记忆(持久化)
94
+ this._working = [] // 工作记忆(会话内临时)
77
95
  }
78
96
 
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)
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)
85
122
  }
86
- } catch (err) {
87
- console.error('[Ambient] 加载记忆失败:', err.message)
123
+ this._store.saveMemories(this._long)
88
124
  }
89
- return []
125
+ return mem
126
+ }
127
+
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)
173
+ }
174
+
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)
90
183
  }
184
+
185
+ getAll() { return { long: this._long, working: this._working } }
186
+ clearWorking() { this._working = [] }
91
187
  }
92
188
 
93
- // ============================================================================
94
- // GoalManager - 管理目标及其生命周期状态
95
- // ============================================================================
189
+ // ─────────────────────────────────────────────────────────────────────────────
190
+ // GoalManager 增强版(支持子目标)
191
+ // ─────────────────────────────────────────────────────────────────────────────
192
+
96
193
  class GoalManager {
97
194
  constructor(stateStore) {
98
195
  this._goals = new Map()
99
- this._stateStore = stateStore
100
- this._loadGoals()
196
+ this._store = stateStore
197
+ this._load()
101
198
  }
102
199
 
103
- _loadGoals() {
104
- const savedGoals = this._stateStore.loadGoals()
105
- for (const goal of savedGoals) {
106
- this._goals.set(goal.id, goal)
107
- }
200
+ _load() {
201
+ for (const g of this._store.loadGoals()) this._goals.set(g.id, g)
108
202
  }
109
203
 
110
204
  _persist() {
111
- const goalsArray = Array.from(this._goals.values())
112
- this._stateStore.saveGoals(goalsArray)
205
+ this._store.saveGoals(Array.from(this._goals.values()))
113
206
  }
114
207
 
115
- createGoal(goalData) {
208
+ createGoal(data, parentId = null) {
116
209
  const goal = {
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: []
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
134
231
  }
135
232
  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
+ }
136
240
  this._persist()
137
241
  return goal
138
242
  }
139
243
 
140
- getGoal(id) {
141
- return this._goals.get(id)
142
- }
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) }
143
248
 
144
- getAllGoals() {
145
- return Array.from(this._goals.values())
146
- }
147
-
148
- getActiveGoals() {
149
- return Array.from(this._goals.values()).filter(g => g.state === GoalState.ACTIVE)
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
150
255
  }
151
256
 
152
- getPendingGoals() {
153
- return Array.from(this._goals.values()).filter(g => g.state === GoalState.PENDING)
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
154
265
  }
155
266
 
156
- updateGoal(id, updates) {
157
- const goal = this._goals.get(id)
158
- if (!goal) return null
159
- Object.assign(goal, updates, { updatedAt: new Date() })
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()
160
273
  this._persist()
161
- return goal
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
162
288
  }
163
289
 
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()
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()
170
298
  this._persist()
171
- return goal
299
+ return g
172
300
  }
173
301
 
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()
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()
180
307
  this._persist()
181
- return goal
308
+ return g
182
309
  }
183
310
 
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()
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()
191
316
  this._persist()
192
- return goal
317
+ return g
193
318
  }
194
319
 
195
320
  deleteGoal(id) {
@@ -199,209 +324,595 @@ class GoalManager {
199
324
  }
200
325
 
201
326
  addEventToGoal(goalId, event) {
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
- })
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()
208
342
  this._persist()
209
343
  }
210
344
  }
211
345
 
212
- // ============================================================================
213
- // EventWatcher - 订阅框架事件,筛选相关事件
214
- // ============================================================================
215
- class EventWatcher {
216
- constructor(goalManager, framework) {
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
217
389
  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
- ])
228
390
  }
229
391
 
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
- ]
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
+ }))
241
417
 
242
- for (const [event, handler] of events) {
243
- this._framework.on(event, handler)
244
- this._handlers.push({ event, handler })
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
245
441
  }
246
442
  }
247
443
 
248
- stop() {
249
- for (const { event, handler } of this._handlers) {
250
- this._framework.off(event, handler)
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)
251
492
  }
252
- this._handlers = []
493
+
494
+ // Agent 忙,跳过这次决策
495
+ if (llmResponse === null) {
496
+ return null
497
+ }
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
253
519
  }
254
520
 
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 })
261
- }
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": []
262
585
  }
263
586
  }
587
+ }
588
+
589
+ 注意:
590
+ - 如果目标已完成,设 shouldComplete=true,action 可为 null
591
+ - 如果目标无法完成(缺少工具/权限/信息),设 shouldFail=true 并填写 failReason
592
+ - 如果需要等待更多事件,action.type 设为 "wait"
593
+ - 如果任务可以分解,优先用 create_subgoal 分解
594
+ - 不要重复刚刚执行过的相同行动`
595
+ }
264
596
 
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
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
273
617
  }
618
+ throw new Error('LLM call failed: ' + e.message)
274
619
  }
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
620
+ }
621
+
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
282
646
  }
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
+ }
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 }
283
673
  }
284
- return true
285
674
  }
286
675
  }
287
676
 
288
- // ============================================================================
289
- // Reflector - 评估操作结果,更新目标状态
290
- // ============================================================================
677
+ // ─────────────────────────────────────────────────────────────────────────────
678
+ // Reflector v2 — 失败分类 + 差异化恢复策略
679
+ // ─────────────────────────────────────────────────────────────────────────────
680
+
291
681
  class Reflector {
292
- constructor(goalManager) {
682
+ constructor(goalManager, memory, stateStore) {
293
683
  this._goalManager = goalManager
684
+ this._memory = memory
685
+ this._store = stateStore
294
686
  }
295
687
 
296
- evaluateOutcome(goal, actionResult) {
297
- if (!goal) return null
688
+ /**
689
+ * 评估行动结果,返回恢复策略
690
+ */
691
+ evaluate(goal, actionResult, decision) {
692
+ const now = Date.now()
298
693
 
299
- // 检查错误
300
- if (actionResult && actionResult.error) {
301
- // 增加尝试次数但不立即失败
694
+ // —— 成功路径 ——
695
+ if (actionResult && actionResult.success !== false && !actionResult.error) {
302
696
  goal.attempts++
303
- return {
304
- shouldContinue: goal.attempts < goal.maxAttempts,
305
- actionTaken: false
306
- }
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 }
307
704
  }
308
705
 
309
- // 检查是否成功完成
310
- if (actionResult && actionResult.success === true) {
311
- goal.attempts++
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 }
720
+ }
312
721
 
313
- // 检查目标是否完成
314
- if (goal.actions.length === 0 || goal.attempts >= goal.maxAttempts) {
315
- return { shouldContinue: false, goalComplete: true }
316
- }
722
+ // 不同错误类型的恢复策略
723
+ switch (ftype) {
724
+ case FailureType.TOOL_NOT_FOUND:
725
+ // 工具不存在 → 立即失败,不重试
726
+ return { status: 'fail', reason: `工具不存在: ${errMsg}`, type: ftype }
317
727
 
318
- return { shouldContinue: true, actionTaken: true }
319
- }
728
+ case FailureType.TIMEOUT:
729
+ // 超时 → 指数退避后重试
730
+ return { status: 'retry', backoffMs: Math.min(5000 * Math.pow(2, goal.attempts), 60000) }
320
731
 
321
- // 工具执行无错误 - 视为成功
322
- goal.attempts++
732
+ case FailureType.LLM_REFUSED:
733
+ // LLM 拒绝 → 标记失败
734
+ return { status: 'fail', reason: errMsg, type: ftype }
323
735
 
324
- // 检查目标是否完成(没有更多操作)
325
- if (goal.actions.length === 0 || goal.attempts >= goal.maxAttempts) {
326
- return { shouldContinue: false, goalComplete: true }
736
+ default:
737
+ // 一般执行错误 继续,让 DecisionEngine 重新决策
738
+ return { status: 'continue', actionSucceeded: false, error: errMsg }
327
739
  }
740
+ }
328
741
 
329
- return { shouldContinue: true, actionTaken: true }
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
330
749
  }
750
+ }
331
751
 
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
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' }
764
+
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 }
772
+ }
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)
339
785
  }
340
- } else {
341
- goal.consecutiveSameActions = 1
342
- goal.lastActionId = actionId
786
+
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
+ }
795
+
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
+ })
804
+ }
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}` }
343
817
  }
344
- return false
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
345
824
  }
346
825
  }
347
826
 
348
- // ============================================================================
349
- // ExplorerLoop - 主自主循环,决定并执行操作
350
- // ============================================================================
351
- class ExplorerLoop {
352
- constructor(goalManager, reflector, framework, config) {
827
+ // ─────────────────────────────────────────────────────────────────────────────
828
+ // EventWatcher 同原版,增加优先级权重传递
829
+ // ─────────────────────────────────────────────────────────────────────────────
830
+
831
+ class EventWatcher {
832
+ constructor(goalManager, framework) {
353
833
  this._goalManager = goalManager
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 = []
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
+ ]
362
841
  }
363
842
 
364
843
  start() {
365
- if (this._running) return
366
- this._running = true
367
- this._scheduleNext()
844
+ for (const type of this._watchedEvents) {
845
+ this._handlers.push(
846
+ this._framework.on(type, (data) => this._handle(type, data))
847
+ )
848
+ }
368
849
  }
369
850
 
370
851
  stop() {
371
- this._running = false
372
- if (this._timer) {
373
- clearTimeout(this._timer)
374
- this._timer = null
375
- }
852
+ for (const h of this._handlers) h()
853
+ this._handlers = []
376
854
  }
377
855
 
378
- pause() {
379
- this._running = false
380
- if (this._timer) {
381
- clearTimeout(this._timer)
382
- this._timer = null
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
+ }
383
866
  }
384
867
  }
385
868
 
386
- resume() {
387
- if (!this._running) {
388
- this._running = true
389
- this._scheduleNext()
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
390
874
  }
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
391
880
  }
881
+ }
392
882
 
393
- isRunning() {
394
- return this._running
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 → 退避到期时间
395
901
  }
396
902
 
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
+
397
909
  getStatus() {
398
910
  return {
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
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)
405
916
  }
406
917
  }
407
918
 
@@ -412,731 +923,435 @@ class ExplorerLoop {
412
923
 
413
924
  async _tick() {
414
925
  if (!this._running) return
926
+ this._tickCount++
415
927
 
416
- // 如果处于嵌套执行上下文中,跳过此tick
417
928
  try {
418
- if (this._framework.getExecutionContext) {
419
- const ctx = this._framework.getExecutionContext()
420
- if (ctx && ctx.id) {
421
- // 跳过此tick,重新调度
422
- this._scheduleNext()
423
- return
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 })
424
934
  }
425
935
  }
426
- } catch (e) {
427
- // getExecutionContext可能不存在,继续执行
428
- }
429
936
 
430
- this._tickCount++
431
- this._lastActionTime = Date.now()
937
+ // 调度:按优先级排序活跃目标
938
+ const activeGoals = this._scheduler.schedule(this._goalManager.getActiveGoals())
432
939
 
433
- try {
434
- await this._processGoals()
940
+ for (const goal of activeGoals) {
941
+ // 退避检查
942
+ const backoffUntil = this._backoffMap.get(goal.id)
943
+ if (backoffUntil && Date.now() < backoffUntil) continue
944
+
945
+ await this._processGoal(goal)
946
+ }
435
947
  } catch (err) {
436
- console.error('[Ambient] Tick错误:', err.message)
437
- this._addActivity('error', { message: err.message })
948
+ console.error('[Ambient] Tick error:', err.message)
949
+ this._log('tick_error', { message: err.message })
438
950
  }
439
951
 
440
- // 调度下一次tick
441
952
  this._scheduleNext()
442
953
  }
443
954
 
444
- async _processGoals() {
445
- const activeGoals = this._goalManager.getActiveGoals()
955
+ async _processGoal(goal) {
956
+ const isEventDriven = goal.conditions && goal.conditions.events && goal.conditions.events.length > 0
957
+ const hasEvents = (goal.eventsReceived || []).length > 0
446
958
 
447
- for (const goal of activeGoals) {
448
- // 检查冷却时间
449
- if (Date.now() - this._lastActionTime < this._config.cooldownPeriod) {
450
- continue
451
- }
452
-
453
- // 检查目标是否有未处理的事件
454
- const hasNewEvents = goal.eventsReceived && goal.eventsReceived.length > 0
959
+ // 事件驱动目标:无待处理事件则跳过
960
+ if (isEventDriven && !hasEvents) return
455
961
 
456
- // 获取下一个操作
457
- if (goal.actions && goal.actions.length > 0) {
458
- const action = goal.actions[0] // 简单策略:取第一个操作
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
+ }
459
970
 
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
- }
971
+ if (!decision) return
467
972
 
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
- }
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
+ }
489
980
 
490
- // 执行操作后清除已处理的事件
491
- if (hasNewEvents && outcome.actionTaken) {
492
- goal.eventsReceived = []
493
- this._goalManager.updateGoal(goal.id, { eventsReceived: [] })
494
- }
495
- }
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
496
985
  }
497
986
 
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
- }
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
506
992
  }
507
- }
508
993
 
509
- async _executeAction(action, eventData = null) {
510
- if (!this._framework) {
511
- return { success: false, error: '框架不可用' }
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
512
1001
  }
513
1002
 
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}` }
521
- }
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
- }
1003
+ // ── 4. 执行行动 ──
1004
+ const eventData = hasEvents ? goal.eventsReceived[0] : null
1005
+ this._log('action_start', { goalId: goal.id, type: action.type, name: action.name })
559
1006
 
560
- return { success: false, error: `未知的操作类型: ${action.type}` }
561
- } catch (err) {
562
- return { success: false, error: err.message }
563
- }
564
- }
1007
+ const result = await this._executor.execute(action, eventData)
1008
+ const outcome = this._reflector.evaluate(goal, result, decision)
565
1009
 
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
572
- }
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
573
1016
 
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)
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
1021
+
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 })
1032
+ }
1033
+ break
583
1034
  }
1035
+
1036
+ this._clearEvents(goal)
584
1037
  }
585
1038
 
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
- }
1039
+ _clearEvents(goal) {
1040
+ if ((goal.eventsReceived || []).length > 0) {
1041
+ this._goalManager.updateGoal(goal.id, { eventsReceived: [] })
602
1042
  }
1043
+ }
603
1044
 
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}`)
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)
615
1049
  }
616
1050
  }
617
1051
 
618
- // ============================================================================
619
- // 主插件类
620
- // ============================================================================
1052
+ // ─────────────────────────────────────────────────────────────────────────────
1053
+ // AmbientAgentPlugin v2 — 主插件类
1054
+ // ─────────────────────────────────────────────────────────────────────────────
1055
+
621
1056
  class AmbientAgentPlugin extends Plugin {
622
1057
  constructor(config = {}) {
623
1058
  super()
624
- this.name = 'ambient'
625
- this.version = '1.0.0'
626
- this.description = 'Ambient Agent - 持续后台运行的智能代理,用于主动监控和执行操作'
627
- this.priority = 18
628
- this.system = true
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
629
1064
 
630
1065
  this.config = {
631
- enabled: config.enabled !== false,
632
- tickInterval: config.tickInterval || 5000, // tick间隔(毫秒)
633
- cooldownPeriod: config.cooldownPeriod || 3000, // 冷却时间(毫秒)
1066
+ enabled: config.enabled !== false,
1067
+ tickInterval: config.tickInterval || 5000,
1068
+ cooldownPeriod: config.cooldownPeriod || 3000,
634
1069
  persistencePath: config.persistencePath || '.agent/data/ambient',
635
- defaultGoals: config.defaultGoals || []
1070
+ defaultGoals: config.defaultGoals || [],
1071
+ llmCallTimeout: config.llmCallTimeout || 30000,
1072
+ actionTimeout: config.actionTimeout || 20000
636
1073
  }
637
1074
 
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 = []
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
645
1086
  }
646
1087
 
647
1088
  install(framework) {
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
-
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()
656
1097
  return this
657
1098
  }
658
1099
 
659
1100
  start(framework) {
660
- if (!this.config.enabled) {
661
- console.log('[Ambient] 插件已禁用,跳过启动')
662
- return this
663
- }
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)
664
1114
 
665
- // 如果没有现有目标,创建默认目标
666
1115
  if (this._goalManager.getAllGoals().length === 0 && this.config.defaultGoals.length > 0) {
667
- for (const goalDef of this.config.defaultGoals) {
668
- this._goalManager.createGoal(goalDef)
669
- }
1116
+ for (const g of this.config.defaultGoals) this._goalManager.createGoal(g)
670
1117
  }
671
1118
 
672
- // 启动事件监听器
673
1119
  this._eventWatcher = new EventWatcher(this._goalManager, this._framework)
674
1120
  this._eventWatcher.start()
675
1121
 
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
- })
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
+ )
686
1131
  this._explorerLoop.start()
687
1132
 
688
- // 注册工具
689
1133
  this._registerTools(framework)
690
-
691
- console.log('[Ambient] 插件已启动')
692
1134
  return this
693
1135
  }
694
1136
 
695
1137
  _registerTools(framework) {
696
- // ambient_goals - 列出/创建/更新/删除目标
1138
+ // ── ambient_goals ──
697
1139
  framework.registerTool({
698
1140
  name: 'ambient_goals',
699
- description: '管理Ambient Agent目标 - 列出、创建、更新、删除、激活目标',
1141
+ description: '管理 Ambient Agent 目标 列出/创建/更新/删除/激活/暂停/恢复/分解子目标',
700
1142
  inputSchema: z.object({
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('激活条件(创建/更新时使用)')
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()
719
1156
  }),
720
- execute: async (args) => {
721
- return this._handleGoalsTool(args)
722
- }
1157
+ execute: async (args) => this._handleGoalsTool(args)
723
1158
  })
724
1159
 
725
- // ambient_status - 获取当前循环状态
1160
+ // ── ambient_status ──
726
1161
  framework.registerTool({
727
1162
  name: 'ambient_status',
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(分析)',
1163
+ description: '获取 Ambient Agent 运行状态 — 循环状态/活跃目标/最近活动/执行日志',
739
1164
  inputSchema: z.object({
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')
1165
+ includeLog: z.boolean().optional().describe('是否包含执行日志(最近 20 条)')
744
1166
  }),
745
- execute: async (args) => {
746
- return this._handleThinkTool(args)
747
- }
1167
+ execute: async (args) => this._handleStatusTool(args)
748
1168
  })
749
1169
 
750
- // ambient_remember - 存储/检索/搜索持久化记忆
1170
+ // ── ambient_remember ──
751
1171
  framework.registerTool({
752
1172
  name: 'ambient_remember',
753
- description: 'Ambient Agent存储或检索持久化记忆',
1173
+ description: '操作 Ambient Agent 语义记忆 — 存储/检索/搜索',
754
1174
  inputSchema: z.object({
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时使用)')
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()
760
1183
  }),
761
- execute: async (args) => {
762
- return this._handleRememberTool(args)
763
- }
1184
+ execute: async (args) => this._handleRememberTool(args)
764
1185
  })
765
1186
 
766
- // ambient_control - 暂停/恢复/调整探索循环
1187
+ // ── ambient_control ──
767
1188
  framework.registerTool({
768
1189
  name: 'ambient_control',
769
- description: '控制Ambient Agent探索循环 - 暂停、恢复或调整设置',
1190
+ description: '控制 Ambient Agent 暂停/恢复/调整参数',
770
1191
  inputSchema: z.object({
771
- action: z.enum(['pause', 'resume', 'status', 'adjust']).describe('控制操作'),
772
- tickInterval: z.number().optional().describe('新的tick间隔毫秒数(adjust时使用)'),
773
- cooldownPeriod: z.number().optional().describe('新的冷却时间毫秒数(adjust时使用)')
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()
774
1196
  }),
775
- execute: async (args) => {
776
- return this._handleControlTool(args)
777
- }
1197
+ execute: async (args) => this._handleControlTool(args)
778
1198
  })
779
1199
  }
780
1200
 
781
1201
  _handleGoalsTool(args) {
782
- const { action, goalId, title, description, priority, actions, conditions } = args
1202
+ const { action, goalId, parentId, title, description, priority,
1203
+ successCriteria, actions, conditions, maxAttempts } = args
783
1204
 
784
1205
  switch (action) {
785
1206
  case 'list': {
786
- const allGoals = this._goalManager.getAllGoals()
1207
+ const all = this._goalManager.getAllGoals()
787
1208
  return {
788
1209
  success: true,
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
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
800
1216
  })),
801
- total: allGoals.length,
802
- active: this._goalManager.getActiveGoals().length,
803
- pending: this._goalManager.getPendingGoals().length
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
+ }
804
1224
  }
805
1225
  }
806
-
807
1226
  case 'create': {
808
- if (!title) {
809
- return { success: false, error: '创建目标需要提供标题' }
810
- }
811
- const goal = this._goalManager.createGoal({ title, description, priority, actions, conditions })
1227
+ if (!title) return { success: false, error: 'title is required' }
1228
+ const goal = this._goalManager.createGoal({ title, description, priority, actions, conditions, maxAttempts, successCriteria })
812
1229
  return { success: true, goal }
813
1230
  }
814
-
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
+ }
815
1237
  case 'update': {
816
- if (!goalId) {
817
- return { success: false, error: '更新目标需要提供目标ID' }
818
- }
1238
+ if (!goalId) return { success: false, error: 'goalId is required' }
819
1239
  const updates = {}
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 }
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' }
835
1249
  }
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: '目标未找到或不是待激活状态' }
843
- }
844
-
845
- default:
846
- return { success: false, error: `未知操作: ${action}` }
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}` }
847
1255
  }
848
1256
  }
849
1257
 
850
- _handleStatusTool() {
851
- if (!this._explorerLoop) {
852
- return { success: false, error: '探索循环未初始化' }
853
- }
1258
+ _handleStatusTool(args = {}) {
1259
+ const loop = this._explorerLoop
1260
+ if (!loop) return { success: false, error: 'Loop not initialized' }
854
1261
 
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
- }))
868
-
869
- return {
1262
+ const status = loop.getStatus()
1263
+ const result = {
870
1264
  success: true,
871
1265
  loop: {
872
- running: loopStatus.running,
873
- tickCount: loopStatus.tickCount,
874
- lastTick: loopStatus.lastTick,
875
- tickInterval: this.config.tickInterval,
876
- cooldownPeriod: this.config.cooldownPeriod
877
- },
878
- activeGoals,
879
- pendingGoals,
880
- recentActivities: loopStatus.recentActivities
881
- }
882
- }
883
-
884
- async _handleThinkTool(args) {
885
- const { goalId, mode, topic, depth } = args
886
-
887
- // 获取活跃代理
888
- const agent = this._getActiveAgent()
889
- if (!agent) {
890
- return { success: false, error: '没有可用的活跃代理' }
891
- }
892
-
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: '思考请求已排队,将在代理空闲时处理。'
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
935
1274
  }
936
- }
937
- return result
1275
+ },
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
938
1285
  }
939
1286
 
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}` : '这个目标的优势、劣势和潜在问题是什么?'}`
1287
+ if (args.includeLog) {
1288
+ result.executionLog = this._stateStore.loadLog().slice(-20)
984
1289
  }
985
- return modePrompts[mode] || modePrompts.reflect
986
- }
987
1290
 
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
1291
+ return result
996
1292
  }
997
1293
 
998
1294
  _handleRememberTool(args) {
999
- const { action, content, key, query, limit } = args
1000
- const maxResults = limit || 10
1295
+ const { action, content, key, tags, scope, goalId, query, limit } = args
1001
1296
 
1002
1297
  switch (action) {
1003
1298
  case 'store': {
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 }
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 }
1016
1302
  }
1017
-
1018
1303
  case 'retrieve': {
1019
- const memories = this._memories.slice(-maxResults).reverse()
1020
- return {
1021
- success: true,
1022
- memories,
1023
- total: this._memories.length
1024
- }
1304
+ const mems = this._memory.recent(limit || 10, scope || 'all')
1305
+ return { success: true, memories: mems, total: mems.length }
1025
1306
  }
1026
-
1027
1307
  case 'search': {
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
- }
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 }
1041
1311
  }
1042
-
1043
- default:
1044
- return { success: false, error: `未知操作: ${action}` }
1312
+ default: return { success: false, error: `Unknown action: ${action}` }
1045
1313
  }
1046
1314
  }
1047
1315
 
1048
1316
  _handleControlTool(args) {
1049
- const { action, tickInterval, cooldownPeriod } = args
1317
+ const { action, tickInterval, cooldownPeriod, llmCallTimeout } = args
1318
+ const loop = this._explorerLoop
1050
1319
 
1051
1320
  switch (action) {
1052
- case 'pause': {
1053
- if (!this._explorerLoop) {
1054
- return { success: false, error: '探索循环未初始化' }
1055
- }
1056
- this._explorerLoop.pause()
1057
- return { success: true, message: '探索循环已暂停' }
1058
- }
1059
-
1060
- case 'resume': {
1061
- if (!this._explorerLoop) {
1062
- return { success: false, error: '探索循环未初始化' }
1063
- }
1064
- this._explorerLoop.resume()
1065
- return { success: true, message: '探索循环已恢复' }
1066
- }
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
-
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()
1083
1324
  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
- }
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 }
1096
1329
  }
1097
-
1098
- default:
1099
- return { success: false, error: `未知操作: ${action}` }
1100
- }
1101
- }
1102
-
1103
- _getActiveAgent() {
1104
- if (this._framework._mainAgent) {
1105
- return this._framework._mainAgent
1330
+ case 'clear_log': {
1331
+ this._stateStore._save('execution_log', [])
1332
+ return { success: true, message: 'Log cleared' }
1333
+ }
1334
+ default: return { success: false, error: `Unknown action: ${action}` }
1106
1335
  }
1107
- const agents = this._framework._agents || []
1108
- return agents.length > 0 ? agents[agents.length - 1] : null
1109
1336
  }
1110
1337
 
1111
1338
  reload(framework) {
1112
1339
  this._framework = framework
1113
- if (this._explorerLoop && this._explorerLoop.isRunning()) {
1114
- // 用新的框架引用重新启动
1115
- this._eventWatcher = new EventWatcher(this._goalManager, this._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)
1116
1345
  this._eventWatcher.start()
1117
1346
  }
1118
1347
  }
1119
1348
 
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
- // 清除引用
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()
1134
1353
  this._framework = null
1135
- this._goalManager = null
1136
- this._reflector = null
1137
- this._stateStore = null
1138
- this._memories = []
1139
1354
  }
1140
1355
  }
1141
1356
 
1142
- module.exports = { AmbientAgentPlugin, GoalState }
1357
+ module.exports = { AmbientAgentPlugin, GoalState, FailureType }