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.
- package/.claude/settings.local.json +142 -142
- package/cli/src/commands/chat.js +4 -1
- package/examples/basic.js +110 -110
- package/examples/mcp-example.js +53 -53
- package/examples/skill-example.js +49 -49
- package/examples/test-mcp.js +79 -79
- package/examples/test-reload.js +61 -61
- package/package.json +1 -1
- package/plugins/ai-plugin.js +2 -1
- package/plugins/ambient-agent-plugin.js +1059 -844
- package/plugins/email.js +122 -1
- package/src/core/agent.js +1 -1
- package/src/core/framework.js +3 -3
- package/src/executors/executor-base.js +58 -58
- package/test-server.js +25 -25
- package/test.txt +3 -3
|
@@ -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:
|
|
14
|
-
ACTIVE:
|
|
15
|
-
COMPLETED: 'completed',
|
|
16
|
-
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
|
-
|
|
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
|
|
29
|
-
//
|
|
43
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
44
|
+
// StateStore — 持久化(同原版,增加 executionLog)
|
|
45
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
46
|
+
|
|
30
47
|
class StateStore {
|
|
31
48
|
constructor(persistencePath) {
|
|
32
|
-
this.
|
|
49
|
+
this._path = persistencePath
|
|
33
50
|
this._ensureDir()
|
|
34
51
|
}
|
|
35
52
|
|
|
36
53
|
_ensureDir() {
|
|
37
|
-
if (!fs.existsSync(this.
|
|
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
|
-
|
|
43
|
-
return path.join(this._persistencePath, 'goals.json')
|
|
44
|
-
}
|
|
57
|
+
_file(name) { return path.join(this._path, `${name}.json`) }
|
|
45
58
|
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
64
|
+
_load(name, fallback) {
|
|
51
65
|
try {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
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.
|
|
100
|
-
this.
|
|
196
|
+
this._store = stateStore
|
|
197
|
+
this._load()
|
|
101
198
|
}
|
|
102
199
|
|
|
103
|
-
|
|
104
|
-
const
|
|
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
|
-
|
|
112
|
-
this._stateStore.saveGoals(goalsArray)
|
|
205
|
+
this._store.saveGoals(Array.from(this._goals.values()))
|
|
113
206
|
}
|
|
114
207
|
|
|
115
|
-
createGoal(
|
|
208
|
+
createGoal(data, parentId = null) {
|
|
116
209
|
const goal = {
|
|
117
|
-
id:
|
|
118
|
-
title:
|
|
119
|
-
description:
|
|
120
|
-
priority:
|
|
121
|
-
state:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
return
|
|
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
|
-
|
|
153
|
-
|
|
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
|
-
|
|
157
|
-
const
|
|
158
|
-
if (!
|
|
159
|
-
|
|
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
|
-
|
|
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
|
-
|
|
165
|
-
const
|
|
166
|
-
if (!
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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
|
|
299
|
+
return g
|
|
172
300
|
}
|
|
173
301
|
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
-
if (!
|
|
177
|
-
|
|
178
|
-
|
|
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
|
|
308
|
+
return g
|
|
182
309
|
}
|
|
183
310
|
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
if (!
|
|
187
|
-
|
|
188
|
-
|
|
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
|
|
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
|
|
203
|
-
if (!
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
//
|
|
214
|
-
//
|
|
215
|
-
|
|
216
|
-
|
|
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
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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
|
-
|
|
243
|
-
|
|
244
|
-
this.
|
|
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
|
-
|
|
249
|
-
|
|
250
|
-
|
|
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
|
-
|
|
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
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
-
|
|
297
|
-
|
|
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
|
-
|
|
304
|
-
|
|
305
|
-
|
|
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
|
-
|
|
311
|
-
|
|
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
|
-
|
|
315
|
-
|
|
316
|
-
|
|
722
|
+
// 不同错误类型的恢复策略
|
|
723
|
+
switch (ftype) {
|
|
724
|
+
case FailureType.TOOL_NOT_FOUND:
|
|
725
|
+
// 工具不存在 → 立即失败,不重试
|
|
726
|
+
return { status: 'fail', reason: `工具不存在: ${errMsg}`, type: ftype }
|
|
317
727
|
|
|
318
|
-
|
|
319
|
-
|
|
728
|
+
case FailureType.TIMEOUT:
|
|
729
|
+
// 超时 → 指数退避后重试
|
|
730
|
+
return { status: 'retry', backoffMs: Math.min(5000 * Math.pow(2, goal.attempts), 60000) }
|
|
320
731
|
|
|
321
|
-
|
|
322
|
-
|
|
732
|
+
case FailureType.LLM_REFUSED:
|
|
733
|
+
// LLM 拒绝 → 标记失败
|
|
734
|
+
return { status: 'fail', reason: errMsg, type: ftype }
|
|
323
735
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
736
|
+
default:
|
|
737
|
+
// 一般执行错误 → 继续,让 DecisionEngine 重新决策
|
|
738
|
+
return { status: 'continue', actionSucceeded: false, error: errMsg }
|
|
327
739
|
}
|
|
740
|
+
}
|
|
328
741
|
|
|
329
|
-
|
|
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
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
350
|
-
//
|
|
351
|
-
|
|
352
|
-
|
|
827
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
828
|
+
// EventWatcher — 同原版,增加优先级权重传递
|
|
829
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
830
|
+
|
|
831
|
+
class EventWatcher {
|
|
832
|
+
constructor(goalManager, framework) {
|
|
353
833
|
this._goalManager = goalManager
|
|
354
|
-
this.
|
|
355
|
-
this.
|
|
356
|
-
this.
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
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
|
-
|
|
366
|
-
|
|
367
|
-
|
|
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.
|
|
372
|
-
|
|
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
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
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
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
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
|
-
|
|
394
|
-
|
|
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:
|
|
400
|
-
tickCount:
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
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
|
-
|
|
419
|
-
|
|
420
|
-
if (
|
|
421
|
-
|
|
422
|
-
this.
|
|
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
|
-
|
|
431
|
-
|
|
937
|
+
// 调度:按优先级排序活跃目标
|
|
938
|
+
const activeGoals = this._scheduler.schedule(this._goalManager.getActiveGoals())
|
|
432
939
|
|
|
433
|
-
|
|
434
|
-
|
|
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
|
|
437
|
-
this.
|
|
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
|
|
445
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
458
|
-
|
|
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
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
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
|
-
|
|
492
|
-
|
|
493
|
-
|
|
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
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
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
|
-
|
|
510
|
-
if (
|
|
511
|
-
|
|
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
|
-
|
|
515
|
-
|
|
516
|
-
|
|
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
|
-
|
|
561
|
-
|
|
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
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
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
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
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
|
-
|
|
606
|
-
|
|
607
|
-
|
|
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
|
|
625
|
-
this.version
|
|
626
|
-
this.description = 'Ambient Agent
|
|
627
|
-
this.priority
|
|
628
|
-
this.system
|
|
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:
|
|
632
|
-
tickInterval:
|
|
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:
|
|
1070
|
+
defaultGoals: config.defaultGoals || [],
|
|
1071
|
+
llmCallTimeout: config.llmCallTimeout || 30000,
|
|
1072
|
+
actionTimeout: config.actionTimeout || 20000
|
|
636
1073
|
}
|
|
637
1074
|
|
|
638
|
-
this._framework
|
|
639
|
-
this._stateStore
|
|
640
|
-
this._goalManager
|
|
641
|
-
this.
|
|
642
|
-
this.
|
|
643
|
-
this.
|
|
644
|
-
this.
|
|
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
|
|
649
|
-
this._stateStore
|
|
650
|
-
this._goalManager
|
|
651
|
-
this.
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
this.
|
|
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
|
-
|
|
662
|
-
|
|
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
|
|
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
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
tickInterval: this.config.tickInterval
|
|
684
|
-
|
|
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'
|
|
702
|
-
goalId:
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
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: '
|
|
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
|
-
|
|
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: '
|
|
1173
|
+
description: '操作 Ambient Agent 语义记忆 — 存储/检索/搜索',
|
|
754
1174
|
inputSchema: z.object({
|
|
755
|
-
action:
|
|
756
|
-
content: z.string().optional()
|
|
757
|
-
key:
|
|
758
|
-
|
|
759
|
-
|
|
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:
|
|
772
|
-
tickInterval:
|
|
773
|
-
cooldownPeriod: z.number().optional()
|
|
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,
|
|
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
|
|
1207
|
+
const all = this._goalManager.getAllGoals()
|
|
787
1208
|
return {
|
|
788
1209
|
success: true,
|
|
789
|
-
goals:
|
|
790
|
-
id: g.id,
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
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
|
-
|
|
802
|
-
|
|
803
|
-
|
|
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
|
-
|
|
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)
|
|
821
|
-
if (description !== undefined)
|
|
822
|
-
if (priority !== undefined)
|
|
823
|
-
if (actions !== undefined)
|
|
824
|
-
if (conditions !== undefined)
|
|
825
|
-
|
|
826
|
-
|
|
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
|
-
|
|
839
|
-
|
|
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
|
-
|
|
852
|
-
|
|
853
|
-
}
|
|
1258
|
+
_handleStatusTool(args = {}) {
|
|
1259
|
+
const loop = this._explorerLoop
|
|
1260
|
+
if (!loop) return { success: false, error: 'Loop not initialized' }
|
|
854
1261
|
|
|
855
|
-
const
|
|
856
|
-
const
|
|
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:
|
|
873
|
-
tickCount:
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
1054
|
-
|
|
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
|
-
|
|
1086
|
-
}
|
|
1087
|
-
|
|
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
|
-
|
|
1099
|
-
return { success:
|
|
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.
|
|
1114
|
-
|
|
1115
|
-
|
|
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(
|
|
1121
|
-
|
|
1122
|
-
if (this.
|
|
1123
|
-
|
|
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 }
|