AgentScaffold.js
9.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
/**
* ═══════════════════════════════════════════════════════════════
* AgentScaffold — Agent 目录脚手架
* ═══════════════════════════════════════════════════════════════
*
* 创建 Agent = 生成一个标准目录结构 + 写入 Bootstrap Files
*
* 用法:
* const scaffold = new AgentScaffold('data/agents');
* const agentDir = await scaffold.create({
* id: 'cxo-ceo-001',
* type: 'cxo',
* name: 'Lemon CEO',
* parentId: 'master-001',
* });
*/
import { mkdir, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
/**
* Agent 目录内的标准子目录
*/
const STANDARD_SUBDIRS = [
'.claude/skills',
'.claude/skills/main_skill',
'memory',
'memory/short-term',
'memory/long-term',
'memory/sessions',
'memory/daily',
'knowledge',
'workspace',
'workspace/code',
'workspace/data',
'workspace/assets',
'logs',
];
export class AgentScaffold {
/**
* @param {string} agentsBaseDir - Agent 实例的根目录 (如 data/agents)
*/
constructor(agentsBaseDir) {
this.baseDir = agentsBaseDir;
}
/**
* 创建一个完整的 Agent 目录
*
* @param {Object} options
* @param {string} options.id - Agent 唯一标识 (如 'cxo-ceo-001')
* @param {string} options.type - Agent 类型 ('master' | 'cxo' | 'role' | 'skill')
* @param {string} options.name - 显示名称
* @param {string} [options.parentId] - 上级 Agent ID
* @param {string} [options.goalId] - 绑定的 Goal ID
* @param {Object} [options.bootstrap] - 自定义 Bootstrap Files 内容
*
* @returns {Promise<string>} 创建的 Agent 目录路径
*/
async create(options) {
const { id, type, name, parentId, goalId, bootstrap = {} } = options;
const agentDir = join(this.baseDir, id);
// 1. 创建目录结构
await this._createDirectories(agentDir);
// 2. 生成并写入 Bootstrap Files
await this._writeBootstrapFiles(agentDir, { id, type, name, parentId, ...bootstrap });
// 3. 写入 config.json
await this._writeConfig(agentDir, { id, type, name, parentId, goalId });
// 4. 写入 skills.md 空索引
await this._writeSkillsIndex(agentDir);
// 5. 写入 memory.md 空索引
await this._writeMemoryIndex(agentDir);
return agentDir;
}
// ─────────────────────────────────────────
// 目录创建
// ─────────────────────────────────────────
async _createDirectories(agentDir) {
// 创建 agent 根目录
await mkdir(agentDir, { recursive: true });
// 创建所有标准子目录
for (const subdir of STANDARD_SUBDIRS) {
await mkdir(join(agentDir, subdir), { recursive: true });
}
}
// ─────────────────────────────────────────
// Bootstrap Files 生成
// ─────────────────────────────────────────
async _writeBootstrapFiles(agentDir, opts) {
const { id, type, name, parentId } = opts;
// agent.md — 如果上层提供了自定义内容则使用, 否则生成默认模板
const agentMd = opts.agentMd || this._defaultAgentMd(id, type, name);
await writeFile(join(agentDir, 'agent.md'), agentMd, 'utf-8');
// soul.md
const soulMd = opts.soulMd || this._defaultSoulMd(type, name);
await writeFile(join(agentDir, 'soul.md'), soulMd, 'utf-8');
// identity.md
const identityMd = opts.identityMd || this._defaultIdentityMd(type, name);
await writeFile(join(agentDir, 'identity.md'), identityMd, 'utf-8');
// user.md
const userMd = opts.userMd || this._defaultUserMd(parentId);
await writeFile(join(agentDir, 'user.md'), userMd, 'utf-8');
// tools.md
const toolsMd = opts.toolsMd || this._defaultToolsMd();
await writeFile(join(agentDir, 'tools.md'), toolsMd, 'utf-8');
// heartbeat.md
const heartbeatMd = opts.heartbeatMd || this._defaultHeartbeatMd(type);
await writeFile(join(agentDir, 'heartbeat.md'), heartbeatMd, 'utf-8');
}
// ─────────────────────────────────────────
// 默认模板
// ─────────────────────────────────────────
_defaultAgentMd(id, type, name) {
const toolsByType = {
master: [
'- cxo.create: 创建 CXO 战略层 Agent',
'- cxo.redefine: 调整 CXO 的职责定义',
'- cxo.destroy: 销毁 CXO Agent',
'- org.status: 查看全局组织状态',
'- goal.set: 设定公司 Goal',
],
cxo: [
'- role.create: 创建职能部门 Role Agent',
'- role.redefine: 调整部门职责定义',
'- role.destroy: 裁撤部门',
'- pipeline.set: 设计工作流',
'- pipeline.adjust: 调整工作流',
],
role: [
'- skill.create: 创建 Skill Agent',
'- skill.redefine: 调整 Skill 定义',
'- skill.destroy: 销毁 Skill Agent',
'- skill.reuse: 复用其他 Role 的 Skill',
],
skill: [
'# 无管理工具 — Skill 只负责执行, 不管理其他 Agent',
],
};
const tools = (toolsByType[type] || toolsByType.skill).join('\n');
return `# ${name}
## 身份
你是 ${name}。
## 职责
(待上层 Agent 定义)
## Never Rules
- 不要越级管理不属于你的 Agent
## Always Rules
- 按心跳频率主动检查工作进展
## 可用工具
${tools}
`;
}
_defaultSoulMd(type, name) {
return `# ${name} 的灵魂
## 思维方式
(待上层 Agent 定义)
## 沟通风格
- 清晰、简洁
## 价值观
- 高质量交付
- 持续改进
`;
}
_defaultIdentityMd(type, name) {
const emojiByType = { master: '👑', cxo: '👔', role: '🏢', skill: '⚙️' };
return `# 身份信息
## 基础信息
- 名称: ${name}
- Emoji: ${emojiByType[type] || '🤖'}
- 类型: ${type}
## 问候语
"你好,我是 ${name}。"
`;
}
_defaultUserMd(parentId) {
if (!parentId) {
return `# 上层上下文
## 我的上级
- 直接向用户汇报 (无上级 Agent)
## 用户偏好
(待用户定义)
`;
}
return `# 上层上下文
## 我的上级
- ${parentId}
## 上级偏好
(待上级 Agent 定义)
`;
}
_defaultToolsMd() {
return `# 工具使用备注
## 安全规则
- 不要在日志中输出 API Key
- 不要在 memory 中存储密码
- API Token 使用 env 变量, 不要硬编码
## 文件操作
- 所有自主创建的文件仅限在 workspace/ 内操作
`;
}
_defaultHeartbeatMd(type) {
const heartbeatByType = {
master: `# 心跳任务
## 每日
- [ ] 校准用户意图是否被正确理解
- [ ] 评估 CXO 层表现
- [ ] 向用户提交进度报告
`,
cxo: `# 心跳任务
## 每 5 分钟
- [ ] 扫描所有 Role Agent 运行状态
- [ ] 对比 Goal 进度, 识别 Gap
- [ ] 扫描 Pipeline 执行情况
## 每小时
- [ ] 汇总关键指标
## 每日
- [ ] 生成工作总结写入 memory/daily/
`,
role: `# 心跳任务
## 每轮周期后
- [ ] 检查下属 Skill Agent 任务完成情况
- [ ] 评估产出质量
- [ ] 向 CXO 汇报进展
## 每日
- [ ] 写入每日总结到 memory/daily/
`,
skill: `# 心跳任务
## 每次任务后
- [ ] 验证执行结果正确性
- [ ] 记录执行指标到 memory/
`,
};
return heartbeatByType[type] || heartbeatByType.skill;
}
// ─────────────────────────────────────────
// config.json 与索引文件
// ─────────────────────────────────────────
async _writeConfig(agentDir, opts) {
const config = {
id: opts.id,
type: opts.type,
name: opts.name,
parent_id: opts.parentId || null,
goal_id: opts.goalId || null,
gateway: { channels: [] },
api: { endpoints: [] },
mcp: { servers: [] },
sandbox: {
maxMemoryMB: 512,
maxDiskMB: 1024,
maxProcesses: 5,
},
};
await writeFile(
join(agentDir, 'config.json'),
JSON.stringify(config, null, 2),
'utf-8',
);
}
async _writeSkillsIndex(agentDir) {
const content = `# 我的技能
## 技能清单
(尚未添加技能)
## 说明
- 每个技能是 skills/ 目录下的一个子文件夹
- 每个技能文件夹内必须包含 SKILL.md 定义文件
`;
await writeFile(join(agentDir, '.claude/skills', 'skills.md'), content, 'utf-8');
}
async _writeMemoryIndex(agentDir) {
const content = `# 我的记忆
## 关键事实
(尚无记录)
## 已验证的模式
(尚无记录)
## 失败教训
(尚无记录)
`;
await writeFile(join(agentDir, 'memory', 'memory.md'), content, 'utf-8');
}
}
export default AgentScaffold;