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