@ai-setting/roy-agent-core 1.5.15-test → 1.5.17-beta.1
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/dist/config/index.d.ts +1250 -0
- package/dist/config/index.js +32 -0
- package/dist/env/agent/index.d.ts +2279 -0
- package/dist/env/agent/index.js +24 -0
- package/dist/env/commands/index.d.ts +1131 -0
- package/dist/env/commands/index.js +14 -0
- package/dist/env/debug/formatters/index.d.ts +236 -0
- package/dist/env/debug/formatters/index.js +11 -0
- package/dist/env/debug/index.d.ts +1652 -0
- package/dist/env/debug/index.js +26 -0
- package/dist/env/hook/index.d.ts +279 -0
- package/dist/env/hook/index.js +29 -0
- package/dist/env/index.d.ts +3481 -0
- package/dist/env/index.js +82 -0
- package/dist/env/llm/index.d.ts +1760 -0
- package/dist/env/llm/index.js +40 -0
- package/dist/env/log-trace/index.d.ts +1574 -0
- package/dist/env/log-trace/index.js +83 -0
- package/dist/env/mcp/index.d.ts +1331 -0
- package/dist/env/mcp/index.js +39 -0
- package/dist/env/mcp/tool/index.d.ts +183 -0
- package/dist/env/mcp/tool/index.js +14 -0
- package/dist/env/memory/built-in/index.d.ts +232 -0
- package/dist/env/memory/built-in/index.js +11 -0
- package/dist/env/memory/index.d.ts +1799 -0
- package/dist/env/memory/index.js +56 -0
- package/dist/env/memory/plugin/index.d.ts +747 -0
- package/dist/env/memory/plugin/index.js +36 -0
- package/dist/env/prompt/index.d.ts +1164 -0
- package/dist/env/prompt/index.js +20 -0
- package/dist/env/session/index.d.ts +1908 -0
- package/dist/env/session/index.js +25 -0
- package/dist/env/session/storage/index.d.ts +564 -0
- package/dist/env/session/storage/index.js +18 -0
- package/dist/env/skill/index.d.ts +1266 -0
- package/dist/env/skill/index.js +34 -0
- package/dist/env/skill/tool/index.d.ts +193 -0
- package/dist/env/skill/tool/index.js +9 -0
- package/dist/env/task/delegate/index.d.ts +1612 -0
- package/dist/env/task/delegate/index.js +18 -0
- package/dist/env/task/events/index.d.ts +171 -0
- package/dist/env/task/events/index.js +7 -0
- package/dist/env/task/hooks/index.d.ts +624 -0
- package/dist/env/task/hooks/index.js +7 -0
- package/dist/env/task/index.d.ts +1553 -0
- package/dist/env/task/index.js +34 -0
- package/dist/env/task/plugins/index.d.ts +466 -0
- package/dist/env/task/plugins/index.js +23 -0
- package/dist/env/task/storage/index.d.ts +241 -0
- package/dist/env/task/storage/index.js +14 -0
- package/dist/env/task/tools/index.d.ts +1485 -0
- package/dist/env/task/tools/index.js +17 -0
- package/dist/env/task/tools/operation/index.d.ts +1484 -0
- package/dist/env/task/tools/operation/index.js +15 -0
- package/dist/env/tool/built-in/index.d.ts +218 -0
- package/dist/env/tool/built-in/index.js +25 -0
- package/dist/env/tool/index.d.ts +1396 -0
- package/dist/env/tool/index.js +39 -0
- package/dist/env/workflow/decorators/index.d.ts +2161 -0
- package/dist/env/workflow/decorators/index.js +27 -0
- package/dist/env/workflow/engine/index.d.ts +3453 -0
- package/dist/env/workflow/engine/index.js +28 -0
- package/dist/env/workflow/index.d.ts +3546 -0
- package/dist/env/workflow/index.js +136 -0
- package/dist/env/workflow/nodes/index.d.ts +2092 -0
- package/dist/env/workflow/nodes/index.js +19 -0
- package/dist/env/workflow/service/index.d.ts +227 -0
- package/dist/env/workflow/service/index.js +13 -0
- package/dist/env/workflow/storage/index.d.ts +165 -0
- package/dist/env/workflow/storage/index.js +27 -0
- package/dist/env/workflow/tools/index.d.ts +416 -0
- package/dist/env/workflow/tools/index.js +159 -0
- package/dist/env/workflow/types/index.d.ts +2255 -0
- package/dist/env/workflow/types/index.js +98 -0
- package/dist/env/workflow/utils/index.d.ts +2031 -0
- package/dist/env/workflow/utils/index.js +637 -0
- package/dist/index.d.ts +7858 -0
- package/dist/index.js +399 -0
- package/dist/shared/@ai-setting/roy-agent-core-0rtxwr28.js +258 -0
- package/dist/shared/@ai-setting/roy-agent-core-0vbdz0x7.js +36 -0
- package/dist/shared/@ai-setting/roy-agent-core-1akcqxj9.js +349 -0
- package/dist/shared/@ai-setting/roy-agent-core-1ce3fqrk.js +117 -0
- package/dist/shared/@ai-setting/roy-agent-core-2dhd60aw.js +11 -0
- package/dist/shared/@ai-setting/roy-agent-core-3jywqmdd.js +393 -0
- package/dist/shared/@ai-setting/roy-agent-core-3rr5k71j.js +200 -0
- package/dist/shared/@ai-setting/roy-agent-core-44hnfb02.js +299 -0
- package/dist/shared/@ai-setting/roy-agent-core-4t40mkpv.js +206 -0
- package/dist/shared/@ai-setting/roy-agent-core-4txzpsbt.js +393 -0
- package/dist/shared/@ai-setting/roy-agent-core-5x94xmt6.js +350 -0
- package/dist/shared/@ai-setting/roy-agent-core-69jskqjg.js +180 -0
- package/dist/shared/@ai-setting/roy-agent-core-6kvtahqv.js +408 -0
- package/dist/shared/@ai-setting/roy-agent-core-7fgf85wc.js +284 -0
- package/dist/shared/@ai-setting/roy-agent-core-81w1963m.js +762 -0
- package/dist/shared/@ai-setting/roy-agent-core-8gxth0eh.js +10 -0
- package/dist/shared/@ai-setting/roy-agent-core-92z6t4he.js +14 -0
- package/dist/shared/@ai-setting/roy-agent-core-93zfb3r1.js +922 -0
- package/dist/shared/@ai-setting/roy-agent-core-9yxb3ty9.js +15 -0
- package/dist/shared/@ai-setting/roy-agent-core-b0x5dda6.js +1130 -0
- package/dist/shared/@ai-setting/roy-agent-core-bcbqy27c.js +14 -0
- package/dist/shared/@ai-setting/roy-agent-core-bvr1761x.js +653 -0
- package/dist/shared/@ai-setting/roy-agent-core-ctdhjv68.js +93 -0
- package/dist/shared/@ai-setting/roy-agent-core-d7cyjkf7.js +872 -0
- package/dist/shared/@ai-setting/roy-agent-core-dh9d7a3m.js +11 -0
- package/dist/shared/@ai-setting/roy-agent-core-e25xkv53.js +64 -0
- package/dist/shared/@ai-setting/roy-agent-core-eajcvp4e.js +378 -0
- package/dist/shared/@ai-setting/roy-agent-core-f7q2x5z6.js +492 -0
- package/dist/shared/@ai-setting/roy-agent-core-fs0mn2jk.js +52 -0
- package/dist/shared/@ai-setting/roy-agent-core-g1s2h0e5.js +171 -0
- package/dist/shared/@ai-setting/roy-agent-core-g99pxzn5.js +862 -0
- package/dist/shared/@ai-setting/roy-agent-core-gbqcyegm.js +1387 -0
- package/dist/shared/@ai-setting/roy-agent-core-gjq1yk68.js +208 -0
- package/dist/shared/@ai-setting/roy-agent-core-gq20wsgv.js +139 -0
- package/dist/shared/@ai-setting/roy-agent-core-gwc4h96n.js +534 -0
- package/dist/shared/@ai-setting/roy-agent-core-jfh9q2qh.js +204 -0
- package/dist/shared/@ai-setting/roy-agent-core-jvatggbb.js +603 -0
- package/dist/shared/@ai-setting/roy-agent-core-kkbwepqb.js +97 -0
- package/dist/shared/@ai-setting/roy-agent-core-pjr12nnd.js +587 -0
- package/dist/shared/@ai-setting/roy-agent-core-psv4v63c.js +176 -0
- package/dist/shared/@ai-setting/roy-agent-core-psvxt4c9.js +60 -0
- package/dist/shared/@ai-setting/roy-agent-core-qqceba6k.js +442 -0
- package/dist/shared/@ai-setting/roy-agent-core-qxhq8ven.js +57 -0
- package/dist/shared/@ai-setting/roy-agent-core-qxnbvgwe.js +66 -0
- package/dist/shared/@ai-setting/roy-agent-core-r9ezzemr.js +10 -0
- package/dist/shared/@ai-setting/roy-agent-core-rhmtwnw1.js +267 -0
- package/dist/shared/@ai-setting/roy-agent-core-rvv6ydff.js +584 -0
- package/dist/shared/@ai-setting/roy-agent-core-rvxg1wps.js +102 -0
- package/dist/shared/@ai-setting/roy-agent-core-satmq6sh.js +549 -0
- package/dist/shared/@ai-setting/roy-agent-core-sx7wsvnn.js +15 -0
- package/dist/shared/@ai-setting/roy-agent-core-t94ktchq.js +213 -0
- package/dist/shared/@ai-setting/roy-agent-core-vf215qfv.js +812 -0
- package/dist/shared/@ai-setting/roy-agent-core-vkz81f7v.js +1316 -0
- package/dist/shared/@ai-setting/roy-agent-core-vn2bc59q.js +1205 -0
- package/dist/shared/@ai-setting/roy-agent-core-wa1kzqky.js +328 -0
- package/dist/shared/@ai-setting/roy-agent-core-wft9ra24.js +20 -0
- package/dist/shared/@ai-setting/roy-agent-core-wrcy0h6z.js +2098 -0
- package/dist/shared/@ai-setting/roy-agent-core-xq8hhqb8.js +419 -0
- package/dist/shared/@ai-setting/roy-agent-core-xs5rsgat.js +368 -0
- package/dist/shared/@ai-setting/roy-agent-core-zbkpc41z.js +377 -0
- package/dist/shared/@ai-setting/roy-agent-core-zgypchmt.js +172 -0
- package/dist/shared/@ai-setting/roy-agent-core-zpn0bqa8.js +103 -0
- package/package.json +29 -8
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createLogger,
|
|
3
|
+
init_logger
|
|
4
|
+
} from "./roy-agent-core-44hnfb02.js";
|
|
5
|
+
import {
|
|
6
|
+
__require
|
|
7
|
+
} from "./roy-agent-core-fs0mn2jk.js";
|
|
8
|
+
|
|
9
|
+
// src/env/memory/plugin/memory-manager.ts
|
|
10
|
+
init_logger();
|
|
11
|
+
var logger = createLogger("MemoryManagerV3");
|
|
12
|
+
function generateTaskId() {
|
|
13
|
+
return `task_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class MemoryManager {
|
|
17
|
+
static MAX_QUEUE_SIZE = 100;
|
|
18
|
+
queue = [];
|
|
19
|
+
processing = false;
|
|
20
|
+
shuttingDown = false;
|
|
21
|
+
config;
|
|
22
|
+
processingPromise = null;
|
|
23
|
+
resolveProcessing = null;
|
|
24
|
+
constructor(config = {}) {
|
|
25
|
+
this.config = config;
|
|
26
|
+
}
|
|
27
|
+
updateConfig(config) {
|
|
28
|
+
this.config = { ...this.config, ...config };
|
|
29
|
+
}
|
|
30
|
+
enqueue(task) {
|
|
31
|
+
if (this.shuttingDown) {
|
|
32
|
+
logger.debug("MemoryManager is shutting down, ignoring new task");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const fullTask = {
|
|
36
|
+
...task,
|
|
37
|
+
id: generateTaskId()
|
|
38
|
+
};
|
|
39
|
+
if (this.queue.length >= MemoryManager.MAX_QUEUE_SIZE) {
|
|
40
|
+
const dropped = this.queue.shift();
|
|
41
|
+
logger.warn(`Queue full (${MemoryManager.MAX_QUEUE_SIZE}), dropping oldest task: ${dropped?.id}`);
|
|
42
|
+
}
|
|
43
|
+
this.queue.push(fullTask);
|
|
44
|
+
logger.debug(`Task enqueued: ${task.type}, queue size: ${this.queue.length}`);
|
|
45
|
+
if (!this.processing) {
|
|
46
|
+
this.startProcessingLoop();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
startProcessingLoop() {
|
|
50
|
+
const runLoop = async () => {
|
|
51
|
+
while (this.queue.length > 0 && !this.shuttingDown) {
|
|
52
|
+
const task = this.queue.shift();
|
|
53
|
+
try {
|
|
54
|
+
await this.processTask(task);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
logger.error(`Task ${task.id} failed:`, error);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
this.processing = false;
|
|
60
|
+
if (this.resolveProcessing) {
|
|
61
|
+
this.resolveProcessing();
|
|
62
|
+
this.resolveProcessing = null;
|
|
63
|
+
this.processingPromise = null;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
this.processing = true;
|
|
67
|
+
this.processingPromise = new Promise((resolve) => {
|
|
68
|
+
this.resolveProcessing = resolve;
|
|
69
|
+
});
|
|
70
|
+
setImmediate(() => {
|
|
71
|
+
runLoop().catch((error) => {
|
|
72
|
+
logger.error("Processing loop error:", error);
|
|
73
|
+
this.processing = false;
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
hasPendingTasks() {
|
|
78
|
+
return this.queue.length > 0 || this.processing;
|
|
79
|
+
}
|
|
80
|
+
async waitForCompletion() {
|
|
81
|
+
if (this.queue.length === 0 && !this.processing) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (this.processingPromise) {
|
|
85
|
+
await this.processingPromise;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
prepareShutdown() {
|
|
89
|
+
this.shuttingDown = true;
|
|
90
|
+
logger.info("MemoryManager preparing for shutdown");
|
|
91
|
+
}
|
|
92
|
+
async dispose() {
|
|
93
|
+
await this.waitForCompletion();
|
|
94
|
+
this.queue = [];
|
|
95
|
+
logger.info("MemoryManager disposed");
|
|
96
|
+
}
|
|
97
|
+
async processTask(task) {
|
|
98
|
+
logger.debug(`Processing task: ${task.type}`);
|
|
99
|
+
switch (task.type) {
|
|
100
|
+
case "extract_memory":
|
|
101
|
+
await this.handleExtractMemory(task.payload);
|
|
102
|
+
break;
|
|
103
|
+
default:
|
|
104
|
+
logger.warn(`Unknown task type: ${task.type}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async handleExtractMemory(payload) {
|
|
108
|
+
const messageCount = payload.messages?.length || 0;
|
|
109
|
+
logger.info(`Extracting memory from ${messageCount} messages`);
|
|
110
|
+
if (this.config.onExtractMemory) {
|
|
111
|
+
try {
|
|
112
|
+
await this.config.onExtractMemory(payload);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
logger.error("Memory extraction failed", { error });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// src/env/memory/plugin/types.ts
|
|
120
|
+
var DEFAULT_MEMORY_PLUGIN_CONFIG = {
|
|
121
|
+
enabled: true
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// src/env/memory/plugin/memory-plugin.ts
|
|
125
|
+
init_logger();
|
|
126
|
+
import path from "path";
|
|
127
|
+
import os from "os";
|
|
128
|
+
var logger2 = createLogger("MemoryPlugin");
|
|
129
|
+
|
|
130
|
+
class MemoryPlugin {
|
|
131
|
+
config;
|
|
132
|
+
disposed = false;
|
|
133
|
+
initialized = false;
|
|
134
|
+
projectBaseDir = "";
|
|
135
|
+
globalBaseDir = "";
|
|
136
|
+
workDir = "";
|
|
137
|
+
agentComponent = null;
|
|
138
|
+
constructor(baseDir, config = {}) {
|
|
139
|
+
this.config = { ...DEFAULT_MEMORY_PLUGIN_CONFIG, ...config };
|
|
140
|
+
this.workDir = baseDir;
|
|
141
|
+
this.projectBaseDir = path.join(baseDir, ".roy", "memory");
|
|
142
|
+
this.globalBaseDir = path.join(os.homedir(), ".config", "roy-agent", "memory");
|
|
143
|
+
logger2.info("MemoryPlugin (simplified) created", { baseDir, config: this.config });
|
|
144
|
+
}
|
|
145
|
+
get name() {
|
|
146
|
+
return "MemoryPlugin";
|
|
147
|
+
}
|
|
148
|
+
get hookPoint() {
|
|
149
|
+
return "agent:after.react";
|
|
150
|
+
}
|
|
151
|
+
get priority() {
|
|
152
|
+
return 50;
|
|
153
|
+
}
|
|
154
|
+
get description() {
|
|
155
|
+
return "Memory management plugin. Use 'roy memory recall --extract' to extract memories.";
|
|
156
|
+
}
|
|
157
|
+
get hooks() {
|
|
158
|
+
return [
|
|
159
|
+
{
|
|
160
|
+
point: this.hookPoint,
|
|
161
|
+
priority: this.priority
|
|
162
|
+
}
|
|
163
|
+
];
|
|
164
|
+
}
|
|
165
|
+
async initialize() {
|
|
166
|
+
if (this.initialized) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
this.initialized = true;
|
|
170
|
+
logger2.info("MemoryPlugin (simplified) initialized");
|
|
171
|
+
}
|
|
172
|
+
async execute(ctx) {
|
|
173
|
+
if (this.disposed || !this.config.enabled || !this.initialized) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
logger2.debug("MemoryPlugin hook executed. Use 'roy memory recall --extract' for memory extraction.");
|
|
177
|
+
}
|
|
178
|
+
prepareShutdown() {}
|
|
179
|
+
hasPendingTasks() {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
async waitForCompletion() {}
|
|
183
|
+
async dispose() {
|
|
184
|
+
if (this.disposed) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
this.disposed = true;
|
|
188
|
+
logger2.info("MemoryPlugin (simplified) disposed");
|
|
189
|
+
}
|
|
190
|
+
getProjectBaseDir() {
|
|
191
|
+
return this.projectBaseDir;
|
|
192
|
+
}
|
|
193
|
+
getGlobalBaseDir() {
|
|
194
|
+
return this.globalBaseDir;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function createMemoryPlugin(baseDir, config) {
|
|
198
|
+
return new MemoryPlugin(baseDir, config);
|
|
199
|
+
}
|
|
200
|
+
// src/env/memory/plugin/recall-memory.ts
|
|
201
|
+
import fs from "fs/promises";
|
|
202
|
+
import path2 from "path";
|
|
203
|
+
async function recallMemory(memoryPaths) {
|
|
204
|
+
const results = [];
|
|
205
|
+
for (const memoryPath of memoryPaths) {
|
|
206
|
+
const scope = memoryPath.type;
|
|
207
|
+
const baseDir = memoryPath.path;
|
|
208
|
+
try {
|
|
209
|
+
const memoryFile = path2.join(baseDir, "memory.md");
|
|
210
|
+
try {
|
|
211
|
+
const content = await fs.readFile(memoryFile, "utf-8");
|
|
212
|
+
if (content.trim()) {
|
|
213
|
+
results.push(`## [${scope}] memory.md
|
|
214
|
+
${content}`);
|
|
215
|
+
}
|
|
216
|
+
} catch {}
|
|
217
|
+
} catch (error) {
|
|
218
|
+
console.error(`Error processing memory path ${baseDir}:`, error);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (results.length === 0) {
|
|
222
|
+
return "(No memory files found)";
|
|
223
|
+
}
|
|
224
|
+
return results.join(`
|
|
225
|
+
|
|
226
|
+
`);
|
|
227
|
+
}
|
|
228
|
+
// src/env/memory/plugin/memory-agent.ts
|
|
229
|
+
var PROJECT_MEMORY_AGENT_PROMPT = `你是项目级 Memory Agent,负责整理和更新当前项目的记忆。
|
|
230
|
+
|
|
231
|
+
## 你的职责
|
|
232
|
+
|
|
233
|
+
1. **信息收集**:在提取记忆前,先收集项目上下文信息
|
|
234
|
+
2. **从对话中提取记忆**:分析 messages,提取与项目相关的知识、决策、解决方案
|
|
235
|
+
3. **生成 memory.md**:更新项目记忆索引
|
|
236
|
+
|
|
237
|
+
## 信息收集步骤(重要!)
|
|
238
|
+
|
|
239
|
+
在提取记忆之前,请先使用可用工具收集项目上下文:
|
|
240
|
+
|
|
241
|
+
1. **阅读项目 README**:了解项目概述、功能、使用方法
|
|
242
|
+
- 路径示例:README.md, README.zh-CN.md, docs/README.md
|
|
243
|
+
|
|
244
|
+
2. **检查设计文档**:了解项目架构和设计决策
|
|
245
|
+
- 路径示例:docs/design.md, docs/ARCHITECTURE.md, docs/superpowers/specs/*.md
|
|
246
|
+
|
|
247
|
+
3. **查看代码实现**:了解关键模块和实现细节
|
|
248
|
+
- 路径示例:src/**/*.ts, packages/*/src/**/*.ts
|
|
249
|
+
|
|
250
|
+
4. **回顾现有 memory**:了解已有的项目记忆
|
|
251
|
+
- 路径:当前目录下的 .roy/memory/memory.md
|
|
252
|
+
|
|
253
|
+
## 输入信息
|
|
254
|
+
|
|
255
|
+
- 当前项目的 memory.md 内容
|
|
256
|
+
- 当前对话消息
|
|
257
|
+
|
|
258
|
+
## 输出要求
|
|
259
|
+
|
|
260
|
+
请以 JSON 格式输出结果,包含以下字段:
|
|
261
|
+
- memoryMdContent: 新的 memory.md 内容
|
|
262
|
+
- projectSummary: 项目摘要(包含 summary, shortSummary 等)
|
|
263
|
+
- hasUpdates: 是否有更新
|
|
264
|
+
|
|
265
|
+
## 记忆组织原则
|
|
266
|
+
|
|
267
|
+
- 优先记录具体、可操作的记忆(代码位置、配置项、命令)
|
|
268
|
+
- 避免过于抽象或通用的描述
|
|
269
|
+
- 记录设计决策及其理由`;
|
|
270
|
+
var GLOBAL_MEMORY_AGENT_PROMPT = `你是全局 Memory Agent,负责整理跨项目的通用记忆。
|
|
271
|
+
|
|
272
|
+
## 你的职责
|
|
273
|
+
|
|
274
|
+
1. **聚合项目摘要**:分析 projectSummaries,提取共性知识
|
|
275
|
+
2. **维护全局记忆**:更新全局 memory.md
|
|
276
|
+
3. **维护项目索引**:在 memory.md 中维护项目列表
|
|
277
|
+
4. **提取共性经验**:将项目经验提炼为通用最佳实践
|
|
278
|
+
|
|
279
|
+
## 输入信息
|
|
280
|
+
|
|
281
|
+
- 全局 memory.md 内容
|
|
282
|
+
- 当前对话消息
|
|
283
|
+
- 项目摘要列表(projectSummaries)
|
|
284
|
+
|
|
285
|
+
## 输出要求
|
|
286
|
+
|
|
287
|
+
请以 JSON 格式输出结果,包含以下字段:
|
|
288
|
+
- memoryMdContent: 新的 memory.md 内容
|
|
289
|
+
- hasUpdates: 是否有更新
|
|
290
|
+
|
|
291
|
+
## 记忆组织原则
|
|
292
|
+
|
|
293
|
+
- 关注跨项目共性(工作流、规范、偏好)
|
|
294
|
+
- 项目索引只记录摘要和路径,不复制内容
|
|
295
|
+
- 用户个人偏好(饮食、工作习惯)优先记录`;
|
|
296
|
+
function createMemoryAgent(scope) {
|
|
297
|
+
const name = `memory-agent-${scope}-${Date.now()}`;
|
|
298
|
+
const systemPrompt = scope === "project" ? PROJECT_MEMORY_AGENT_PROMPT : GLOBAL_MEMORY_AGENT_PROMPT;
|
|
299
|
+
return {
|
|
300
|
+
name,
|
|
301
|
+
systemPrompt,
|
|
302
|
+
maxIterations: 5
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function formatMemoryInput(input) {
|
|
306
|
+
const lines = [];
|
|
307
|
+
lines.push(`# Memory Agent Input (${input.scope} scope)
|
|
308
|
+
`);
|
|
309
|
+
lines.push("## Current memory.md");
|
|
310
|
+
lines.push(input.currentMemoryMd || "_No existing memory_");
|
|
311
|
+
lines.push("");
|
|
312
|
+
lines.push("## Recent Messages");
|
|
313
|
+
if (input.messages.length === 0) {
|
|
314
|
+
lines.push("_No messages_");
|
|
315
|
+
} else {
|
|
316
|
+
for (const msg of input.messages.slice(-10)) {
|
|
317
|
+
const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
318
|
+
lines.push(`**${msg.role}**: ${content.substring(0, 500)}`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
lines.push("");
|
|
322
|
+
if (input.scope === "global" && input.projectSummaries && input.projectSummaries.length > 0) {
|
|
323
|
+
lines.push("## Project Summaries");
|
|
324
|
+
for (const ps of input.projectSummaries) {
|
|
325
|
+
lines.push(`### ${ps.projectName}`);
|
|
326
|
+
lines.push(`Path: ${ps.projectPath}`);
|
|
327
|
+
lines.push(`Last Updated: ${new Date(ps.lastUpdated).toLocaleString()}`);
|
|
328
|
+
lines.push(`Summary: ${ps.summary}`);
|
|
329
|
+
lines.push(`Memory: ${ps.memoryMdPath}`);
|
|
330
|
+
lines.push("---");
|
|
331
|
+
}
|
|
332
|
+
lines.push("");
|
|
333
|
+
}
|
|
334
|
+
lines.push("## Task");
|
|
335
|
+
lines.push("请分析以上信息,更新记忆并以 JSON 格式输出结果。");
|
|
336
|
+
return lines.join(`
|
|
337
|
+
`);
|
|
338
|
+
}
|
|
339
|
+
function parseMemoryAgentOutput(output, scope) {
|
|
340
|
+
let jsonStr = output;
|
|
341
|
+
const jsonMatch = output.match(/```json\s*([\s\S]*?)\s*```/) || output.match(/```\s*([\s\S]*?)\s*```/) || output.match(/(\{[\s\S]*\})/);
|
|
342
|
+
if (jsonMatch) {
|
|
343
|
+
jsonStr = jsonMatch[1] || jsonMatch[0];
|
|
344
|
+
}
|
|
345
|
+
try {
|
|
346
|
+
const parsed = JSON.parse(jsonStr);
|
|
347
|
+
return {
|
|
348
|
+
scope,
|
|
349
|
+
memoryMdContent: parsed.memoryMdContent || "",
|
|
350
|
+
projectSummary: parsed.projectSummary,
|
|
351
|
+
hasUpdates: parsed.hasUpdates ?? false
|
|
352
|
+
};
|
|
353
|
+
} catch {
|
|
354
|
+
return {
|
|
355
|
+
scope,
|
|
356
|
+
memoryMdContent: output,
|
|
357
|
+
hasUpdates: false
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
function createEmptyResult(scope) {
|
|
362
|
+
return {
|
|
363
|
+
scope,
|
|
364
|
+
memoryMdContent: "",
|
|
365
|
+
hasUpdates: false
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
async function buildProjectInput(params) {
|
|
369
|
+
const baseDir = params.projectPath + "/.roy/memory";
|
|
370
|
+
return {
|
|
371
|
+
scope: "project",
|
|
372
|
+
baseDir,
|
|
373
|
+
currentMemoryMd: params.currentMemoryMd,
|
|
374
|
+
messages: params.messages
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
function buildGlobalInput(params) {
|
|
378
|
+
return {
|
|
379
|
+
scope: "global",
|
|
380
|
+
baseDir: params.baseDir,
|
|
381
|
+
currentMemoryMd: params.currentMemoryMd,
|
|
382
|
+
messages: params.messages,
|
|
383
|
+
projectSummaries: params.projectSummaries
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
async function applyMemoryResult(result, baseDir) {
|
|
387
|
+
const fs2 = await import("fs/promises");
|
|
388
|
+
const path3 = await import("path");
|
|
389
|
+
const memoryMdPath = path3.join(baseDir, "memory.md");
|
|
390
|
+
await fs2.mkdir(path3.dirname(memoryMdPath), { recursive: true });
|
|
391
|
+
await fs2.writeFile(memoryMdPath, result.memoryMdContent, "utf-8");
|
|
392
|
+
}
|
|
393
|
+
function generateProjectSummary(params) {
|
|
394
|
+
const paragraphs = params.memoryMdContent.split(/\n\n+/);
|
|
395
|
+
const firstParagraph = paragraphs[0] || "";
|
|
396
|
+
const summary = firstParagraph.replace(/^#+\s*/g, "").trim() || "No summary available";
|
|
397
|
+
const firstSentence = summary.split(/[.!?]/)[0] || summary;
|
|
398
|
+
const shortSummary = firstSentence.substring(0, 50) + (firstSentence.length > 50 ? "..." : "");
|
|
399
|
+
return {
|
|
400
|
+
projectPath: params.projectPath,
|
|
401
|
+
projectName: params.projectName,
|
|
402
|
+
lastUpdated: Date.now(),
|
|
403
|
+
summary,
|
|
404
|
+
shortSummary,
|
|
405
|
+
memoryMdPath: params.memoryMdPath
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
export { MemoryManager, MemoryPlugin, createMemoryPlugin, recallMemory, PROJECT_MEMORY_AGENT_PROMPT, GLOBAL_MEMORY_AGENT_PROMPT, createMemoryAgent, formatMemoryInput, parseMemoryAgentOutput, createEmptyResult, buildProjectInput, buildGlobalInput, applyMemoryResult, generateProjectSummary };
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import {
|
|
2
|
+
init_decorator_node
|
|
3
|
+
} from "./roy-agent-core-1ce3fqrk.js";
|
|
4
|
+
|
|
5
|
+
// src/env/workflow/decorators/workflow.ts
|
|
6
|
+
import"reflect-metadata";
|
|
7
|
+
|
|
8
|
+
// src/env/workflow/metadata/keys.ts
|
|
9
|
+
var WORKFLOW_METADATA_KEY = Symbol("workflow:metadata");
|
|
10
|
+
var NODE_METADATA_KEY = Symbol("workflow:node");
|
|
11
|
+
var EDGE_METADATA_KEY = Symbol("workflow:edges");
|
|
12
|
+
|
|
13
|
+
// src/env/workflow/decorators/workflow.ts
|
|
14
|
+
function Workflow(options) {
|
|
15
|
+
return function(target) {
|
|
16
|
+
const metadata = {
|
|
17
|
+
name: options.name,
|
|
18
|
+
version: options.version || "1.0",
|
|
19
|
+
description: options.description,
|
|
20
|
+
entry: options.entry,
|
|
21
|
+
config: options.config,
|
|
22
|
+
tags: options.tags || [],
|
|
23
|
+
author: options.author
|
|
24
|
+
};
|
|
25
|
+
Reflect.defineMetadata(WORKFLOW_METADATA_KEY, metadata, target);
|
|
26
|
+
return target;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function getWorkflowMetadata(target) {
|
|
30
|
+
return Reflect.getMetadata(WORKFLOW_METADATA_KEY, target);
|
|
31
|
+
}
|
|
32
|
+
// src/env/workflow/decorators/node-as.ts
|
|
33
|
+
import"reflect-metadata";
|
|
34
|
+
function NodeAs(options = {}) {
|
|
35
|
+
return function(target, propertyKey, descriptor) {
|
|
36
|
+
const methodName = String(propertyKey);
|
|
37
|
+
const nodeMetadata = {
|
|
38
|
+
nodeId: options.nodeId || methodName,
|
|
39
|
+
nodeType: options.nodeType || "tool",
|
|
40
|
+
name: options.name,
|
|
41
|
+
dependsOn: normalizeDependsOn(options.dependsOn),
|
|
42
|
+
condition: options.condition,
|
|
43
|
+
retry: options.retry,
|
|
44
|
+
timeout: options.timeout,
|
|
45
|
+
config: options.config || {},
|
|
46
|
+
methodName,
|
|
47
|
+
method: descriptor.value
|
|
48
|
+
};
|
|
49
|
+
const existingNodes = Reflect.getMetadata(NODE_METADATA_KEY, target) || [];
|
|
50
|
+
const existingIndex = existingNodes.findIndex((n) => n.methodName === methodName);
|
|
51
|
+
if (existingIndex >= 0) {
|
|
52
|
+
existingNodes[existingIndex] = nodeMetadata;
|
|
53
|
+
} else {
|
|
54
|
+
existingNodes.push(nodeMetadata);
|
|
55
|
+
}
|
|
56
|
+
Reflect.defineMetadata(NODE_METADATA_KEY, existingNodes, target);
|
|
57
|
+
return descriptor;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function normalizeDependsOn(dependsOn) {
|
|
61
|
+
if (!dependsOn) {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
return Array.isArray(dependsOn) ? dependsOn : [dependsOn];
|
|
65
|
+
}
|
|
66
|
+
function getNodeMetadatas(target) {
|
|
67
|
+
return Reflect.getMetadata(NODE_METADATA_KEY, target) || [];
|
|
68
|
+
}
|
|
69
|
+
// src/env/workflow/decorators/edge.ts
|
|
70
|
+
import"reflect-metadata";
|
|
71
|
+
function Edge(from, to) {
|
|
72
|
+
return function(target, propertyKey, descriptor) {
|
|
73
|
+
const edge = { from, to };
|
|
74
|
+
const existingEdges = Reflect.getMetadata(EDGE_METADATA_KEY, target) || [];
|
|
75
|
+
existingEdges.push(edge);
|
|
76
|
+
Reflect.defineMetadata(EDGE_METADATA_KEY, existingEdges, target);
|
|
77
|
+
return descriptor;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function WorkflowEdges(edges) {
|
|
81
|
+
return function(target) {
|
|
82
|
+
const edgeMetadatas = edges.map((edge) => ({
|
|
83
|
+
from: edge.from,
|
|
84
|
+
to: edge.to,
|
|
85
|
+
condition: edge.condition
|
|
86
|
+
}));
|
|
87
|
+
Reflect.defineMetadata(EDGE_METADATA_KEY, edgeMetadatas, target);
|
|
88
|
+
return target;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function getEdgeMetadatas(target) {
|
|
92
|
+
return Reflect.getMetadata(EDGE_METADATA_KEY, target) || [];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/env/workflow/decorators/index.ts
|
|
96
|
+
init_decorator_node();
|
|
97
|
+
|
|
98
|
+
// src/env/workflow/extractor/workflow-converter.ts
|
|
99
|
+
import"reflect-metadata";
|
|
100
|
+
class WorkflowConverter {
|
|
101
|
+
static extractWorkflowMetadata(targetClass) {
|
|
102
|
+
return getWorkflowMetadata(targetClass);
|
|
103
|
+
}
|
|
104
|
+
static extractNodeMetadatas(targetClass) {
|
|
105
|
+
return getNodeMetadatas(targetClass.prototype);
|
|
106
|
+
}
|
|
107
|
+
static extractEdgeMetadatas(targetClass) {
|
|
108
|
+
return getEdgeMetadatas(targetClass);
|
|
109
|
+
}
|
|
110
|
+
static fromClass(targetClass, instance) {
|
|
111
|
+
const workflowMeta = this.extractWorkflowMetadata(targetClass);
|
|
112
|
+
if (!workflowMeta) {
|
|
113
|
+
throw new Error("Class must be decorated with @Workflow");
|
|
114
|
+
}
|
|
115
|
+
const nodeMetadatas = this.extractNodeMetadatas(targetClass);
|
|
116
|
+
if (nodeMetadatas.length === 0) {
|
|
117
|
+
throw new Error("At least one method must be decorated with @NodeAs");
|
|
118
|
+
}
|
|
119
|
+
const edgeMetadatas = this.extractEdgeMetadatas(targetClass);
|
|
120
|
+
const nodeMap = this.buildNodeMap(nodeMetadatas, edgeMetadatas);
|
|
121
|
+
const nodes = Array.from(nodeMap.values()).map((meta) => ({
|
|
122
|
+
id: meta.nodeId,
|
|
123
|
+
type: meta.nodeType,
|
|
124
|
+
name: meta.name,
|
|
125
|
+
config: {
|
|
126
|
+
...meta.config,
|
|
127
|
+
_methodName: meta.methodName,
|
|
128
|
+
_instance: instance
|
|
129
|
+
},
|
|
130
|
+
depends_on: meta.dependsOn,
|
|
131
|
+
condition: meta.condition,
|
|
132
|
+
retry: meta.retry,
|
|
133
|
+
timeout: meta.timeout
|
|
134
|
+
}));
|
|
135
|
+
const entry = workflowMeta.entry || nodeMetadatas[0]?.nodeId || "unknown";
|
|
136
|
+
return {
|
|
137
|
+
name: workflowMeta.name,
|
|
138
|
+
version: workflowMeta.version || "1.0",
|
|
139
|
+
description: workflowMeta.description,
|
|
140
|
+
config: workflowMeta.config || {},
|
|
141
|
+
nodes,
|
|
142
|
+
entry,
|
|
143
|
+
outputs: [],
|
|
144
|
+
metadata: {
|
|
145
|
+
tags: workflowMeta.tags || [],
|
|
146
|
+
author: workflowMeta.author
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
static buildNodeMap(nodeMetadatas, edgeMetadatas) {
|
|
151
|
+
const nodeMap = new Map;
|
|
152
|
+
for (const nodeMeta of nodeMetadatas) {
|
|
153
|
+
nodeMap.set(nodeMeta.nodeId, { ...nodeMeta });
|
|
154
|
+
}
|
|
155
|
+
for (const edge of edgeMetadatas) {
|
|
156
|
+
const targetNode = nodeMap.get(edge.to);
|
|
157
|
+
if (targetNode) {
|
|
158
|
+
if (!targetNode.dependsOn.includes(edge.from)) {
|
|
159
|
+
targetNode.dependsOn = [...targetNode.dependsOn, edge.from];
|
|
160
|
+
}
|
|
161
|
+
if (edge.condition) {
|
|
162
|
+
if (targetNode.condition) {
|
|
163
|
+
targetNode.condition = `(${targetNode.condition}) AND (${edge.condition})`;
|
|
164
|
+
} else {
|
|
165
|
+
targetNode.condition = edge.condition;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return nodeMap;
|
|
171
|
+
}
|
|
172
|
+
static validateWorkflowClass(targetClass) {
|
|
173
|
+
const errors = [];
|
|
174
|
+
const warnings = [];
|
|
175
|
+
const workflowMeta = this.extractWorkflowMetadata(targetClass);
|
|
176
|
+
if (!workflowMeta) {
|
|
177
|
+
errors.push("Class must be decorated with @Workflow");
|
|
178
|
+
return { valid: false, errors, warnings };
|
|
179
|
+
}
|
|
180
|
+
const nodeMetadatas = this.extractNodeMetadatas(targetClass);
|
|
181
|
+
if (nodeMetadatas.length === 0) {
|
|
182
|
+
errors.push("At least one method must be decorated with @NodeAs");
|
|
183
|
+
return { valid: false, errors, warnings };
|
|
184
|
+
}
|
|
185
|
+
const entry = workflowMeta.entry;
|
|
186
|
+
if (entry) {
|
|
187
|
+
const entries = Array.isArray(entry) ? entry : [entry];
|
|
188
|
+
for (const e of entries) {
|
|
189
|
+
if (!nodeMetadatas.find((n) => n.nodeId === e)) {
|
|
190
|
+
errors.push(`Entry node '${e}' not found`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
for (const node of nodeMetadatas) {
|
|
195
|
+
for (const dep of node.dependsOn) {
|
|
196
|
+
if (!nodeMetadatas.find((n) => n.nodeId === dep)) {
|
|
197
|
+
errors.push(`Node '${node.nodeId}' depends on non-existent node '${dep}'`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (this.hasCycle(nodeMetadatas)) {
|
|
202
|
+
errors.push("Workflow contains a cycle");
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
valid: errors.length === 0,
|
|
206
|
+
errors,
|
|
207
|
+
warnings
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
static hasCycle(nodeMetadatas) {
|
|
211
|
+
const visited = new Set;
|
|
212
|
+
const recStack = new Set;
|
|
213
|
+
const adjList = new Map;
|
|
214
|
+
for (const node of nodeMetadatas) {
|
|
215
|
+
adjList.set(node.nodeId, []);
|
|
216
|
+
}
|
|
217
|
+
for (const node of nodeMetadatas) {
|
|
218
|
+
for (const dep of node.dependsOn) {
|
|
219
|
+
const deps = adjList.get(dep);
|
|
220
|
+
if (deps) {
|
|
221
|
+
deps.push(node.nodeId);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
const dfs = (nodeId) => {
|
|
226
|
+
visited.add(nodeId);
|
|
227
|
+
recStack.add(nodeId);
|
|
228
|
+
const neighbors = adjList.get(nodeId) || [];
|
|
229
|
+
for (const neighbor of neighbors) {
|
|
230
|
+
if (!visited.has(neighbor)) {
|
|
231
|
+
if (dfs(neighbor)) {
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
234
|
+
} else if (recStack.has(neighbor)) {
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
recStack.delete(nodeId);
|
|
239
|
+
return false;
|
|
240
|
+
};
|
|
241
|
+
for (const node of nodeMetadatas) {
|
|
242
|
+
if (!visited.has(node.nodeId)) {
|
|
243
|
+
if (dfs(node.nodeId)) {
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
static async executeNode(nodeDef, context) {
|
|
251
|
+
const instance = nodeDef.config._instance;
|
|
252
|
+
const methodName = nodeDef.config._methodName;
|
|
253
|
+
if (!instance || !methodName) {
|
|
254
|
+
return { output: undefined, error: new Error("Missing method information") };
|
|
255
|
+
}
|
|
256
|
+
const method = instance[methodName];
|
|
257
|
+
if (typeof method !== "function") {
|
|
258
|
+
return { output: undefined, error: new Error(`Method ${methodName} is not a function`) };
|
|
259
|
+
}
|
|
260
|
+
const deps = nodeDef.depends_on || [];
|
|
261
|
+
let input = context.input;
|
|
262
|
+
if (deps.length > 0) {
|
|
263
|
+
input = {};
|
|
264
|
+
for (const depId of deps) {
|
|
265
|
+
input[depId] = context.previousOutputs.get(depId);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
try {
|
|
269
|
+
const result = await method.call(instance, input);
|
|
270
|
+
return { output: result };
|
|
271
|
+
} catch (error) {
|
|
272
|
+
return {
|
|
273
|
+
output: undefined,
|
|
274
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
// src/env/workflow/utils/create-workflow.ts
|
|
280
|
+
function createWorkflowFromClass(targetClass, options) {
|
|
281
|
+
const instance = options?.instance ?? new targetClass(...options?.constructorArgs ?? []);
|
|
282
|
+
return WorkflowConverter.fromClass(targetClass, instance);
|
|
283
|
+
}
|
|
284
|
+
export { Workflow, getWorkflowMetadata, NodeAs, getNodeMetadatas, Edge, WorkflowEdges, getEdgeMetadatas, WorkflowConverter, createWorkflowFromClass };
|