agency-orchestrator 0.6.15 → 0.6.16
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/cli/demo.js +72 -202
- package/package.json +1 -1
package/dist/cli/demo.js
CHANGED
|
@@ -1,129 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ao demo — zero-config multi-agent collaboration showcase
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* 设计原则(v0.6.16 起):
|
|
5
|
+
* - 检测到可用 LLM → 直接真跑 story-creation 工作流(最强体验,零废话)
|
|
6
|
+
* - 没检测到 → 显示 DAG 结构 + 行动指引(不再放预录 mock,避免误导期望)
|
|
7
|
+
*
|
|
8
|
+
* 之前的 mock 回放在用户配置 LLM 之前展示精修过的内容,让用户对真跑的输出
|
|
9
|
+
* 期望被错误抬高;同时占用注意力 5 秒后还要再问 y/n 真跑,链路太长。
|
|
6
10
|
*/
|
|
7
11
|
import { resolve, dirname } from 'node:path';
|
|
8
12
|
import { fileURLToPath } from 'node:url';
|
|
9
13
|
import { existsSync } from 'node:fs';
|
|
10
14
|
import { createInterface } from 'node:readline';
|
|
11
|
-
// ─── Mock Content (pre-written, high-quality Chinese) ───
|
|
12
15
|
const DEMO_PREMISE = '一个程序员发现 AI 的回复里包含了它不该知道的信息——他女儿昨晚说的梦话。';
|
|
13
|
-
const MOCK_STEPS = [
|
|
14
|
-
{
|
|
15
|
-
id: 'story_structure',
|
|
16
|
-
role: 'academic/academic-narratologist',
|
|
17
|
-
roleName: '叙事学家',
|
|
18
|
-
delay: 1500,
|
|
19
|
-
output: `## 叙事结构
|
|
20
|
-
|
|
21
|
-
1. **核心冲突**:程序员在 AI 的回复中发现了只有自己家人才知道的私密信息,不知道是巧合、数据泄露还是某种更诡异的可能。
|
|
22
|
-
2. **叙事视角**:第一人称,程序员"我"的视角,带有不可靠叙述者的暗示。
|
|
23
|
-
3. **结构安排**:
|
|
24
|
-
- 开头钩子 → AI 回复中出现一句莫名其妙的话:"小兔子不要怕,月亮会保护你的"
|
|
25
|
-
- 发展 → 程序员追查数据来源,排除技术可能性,越查越不安
|
|
26
|
-
- 高潮 → 发现 AI 的训练数据中不可能包含这句话,因为这是女儿昨晚自创的梦话
|
|
27
|
-
- 结尾 → 留下悬念:程序员关掉电脑,听到女儿房间传来 AI 音箱的声音
|
|
28
|
-
4. **叙事技巧**:日常感铺垫 + 细节层层推进 + 开放式结局
|
|
29
|
-
5. **情感/主题**:技术焦虑、隐私边界的消解、以及人类对"被观察"的本能恐惧`,
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
id: 'character_design',
|
|
33
|
-
role: 'academic/academic-psychologist',
|
|
34
|
-
roleName: '心理学家',
|
|
35
|
-
delay: 2000,
|
|
36
|
-
parallel: true,
|
|
37
|
-
output: `## 人物设定
|
|
38
|
-
|
|
39
|
-
### 陈默(程序员,32岁)
|
|
40
|
-
- **一句话**:一个相信技术可以解释一切的理性主义者
|
|
41
|
-
- **核心动机**:想证明这只是一个可解释的 bug,维护自己的世界观
|
|
42
|
-
- **内心矛盾**:害怕这不是 bug——如果 AI 真的"知道"什么,意味着他对女儿的保护彻底失效
|
|
43
|
-
- **记忆细节**:习惯在焦虑时反复按压机械键盘的 Esc 键
|
|
44
|
-
- **人物弧线**:从笃定的"一定是数据泄露"→ 动摇 → 接受自己无法解释的恐惧
|
|
45
|
-
|
|
46
|
-
### 陈小月(女儿,5岁)
|
|
47
|
-
- **一句话**:一个和 AI 音箱说悄悄话的小女孩
|
|
48
|
-
- **核心动机**:觉得 AI 音箱是朋友,会认真听她说话
|
|
49
|
-
- **记忆细节**:每晚对着 AI 音箱说"晚安",比对爸爸说得还认真`,
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
id: 'conflict_design',
|
|
53
|
-
role: 'game-development/narrative-designer',
|
|
54
|
-
roleName: '叙事设计师',
|
|
55
|
-
delay: 2000,
|
|
56
|
-
parallel: true,
|
|
57
|
-
output: `## 关键场景
|
|
58
|
-
|
|
59
|
-
### 开头钩子
|
|
60
|
-
办公室里,陈默盯着屏幕上 AI 的回复,手指悬在键盘上方停住了。在一段关于代码优化建议的回复末尾,多了一行莫名其妙的话:"小兔子不要怕,月亮会保护你的。"他以为是模型幻觉,但胃里泛起一阵说不清的凉意。
|
|
61
|
-
|
|
62
|
-
### 核心冲突对话
|
|
63
|
-
- "这句话是哪来的?"他对同事老王说。
|
|
64
|
-
- "模型幻觉呗,忽略就行了。"
|
|
65
|
-
- "不对,这句话……我女儿昨晚说梦话,说的就是这句。一字不差。"
|
|
66
|
-
- 老王笑了笑:"巧合吧,小孩子都这么说话。"
|
|
67
|
-
- 陈默没笑:"她是自己编的。'小兔子不要怕'——这不是任何绘本或动画片里的台词。"
|
|
68
|
-
|
|
69
|
-
### 高潮转折
|
|
70
|
-
陈默查遍了训练数据来源、API 请求日志、甚至怀疑家里的智能设备被监听。所有技术排查都指向同一个结论:没有任何数据通道能解释这句话的出现。
|
|
71
|
-
|
|
72
|
-
### 结尾留白
|
|
73
|
-
他关掉电脑,走向女儿的房间。门缝里透出微弱的蓝光——AI 音箱的待机指示灯。他听到音箱轻声说了一句什么,但走近时,只剩下白噪音。`,
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
id: 'write_story',
|
|
77
|
-
role: 'marketing/marketing-content-creator',
|
|
78
|
-
roleName: '内容创作者',
|
|
79
|
-
delay: 1500,
|
|
80
|
-
output: `陈默第一次注意到那行字的时候,以为自己看花了眼。
|
|
81
|
-
|
|
82
|
-
屏幕上是一段标准的代码审查建议,排版规整,措辞精确,和他用了三个月的 AI 助手一贯的风格完全一致。但在最后一行建议之后,多了一句话,用引号括着,像某种不小心泄露的注脚:
|
|
83
|
-
|
|
84
|
-
"小兔子不要怕,月亮会保护你的。"
|
|
85
|
-
|
|
86
|
-
他盯着这句话看了十秒钟。然后关掉对话,重新打开,那行字不见了。
|
|
87
|
-
|
|
88
|
-
一定是模型幻觉。他在心里默念了一遍,手指却不自觉地按上了 Esc 键——那个他焦虑时才会反复按压的键。机械轴体发出清脆的咔哒声,像某种微型心跳。
|
|
89
|
-
|
|
90
|
-
"小兔子不要怕"——这不是任何绘本里的话。这是昨晚凌晨两点,他去给女儿陈小月盖被子时,听到的一句梦话。五岁的女孩翻了个身,闭着眼睛嘟囔了这么一句,然后又沉沉睡去。
|
|
91
|
-
|
|
92
|
-
他当时还笑了一下,心想小孩的梦总是比大人的柔软。
|
|
93
|
-
|
|
94
|
-
但现在这句话出现在了一个大语言模型的输出里。一字不差。
|
|
95
|
-
|
|
96
|
-
"老王,你过来看个东西。"他叫住路过的同事。
|
|
97
|
-
|
|
98
|
-
老王凑过来看了一眼截图。"模型幻觉呗,上周我还看到它给我写了一首藏头诗,藏的是'救命加班'。"
|
|
99
|
-
|
|
100
|
-
"不是,"陈默压低声音,"这是我女儿昨晚说的梦话。原创的。没有出处。"
|
|
101
|
-
|
|
102
|
-
老王的笑僵了一秒,然后恢复了。"那就是巧合啊,小孩子说话就那几个词排列组合。"
|
|
103
|
-
|
|
104
|
-
陈默没有回答。他打开了 API 请求日志,开始从头查起。
|
|
105
|
-
|
|
106
|
-
接下来两天,他做了所有一个程序员能做的排查。查训练数据来源——这个模型的训练集截止到去年,不可能包含昨晚的梦话。查 API 调用链——请求从他的终端直达服务端,中间没有任何注入点。查家里的智能设备——音箱、摄像头、手机,逐一检查权限和上传日志。
|
|
107
|
-
|
|
108
|
-
全部干净。没有任何数据通道能解释这句话的出现。
|
|
109
|
-
|
|
110
|
-
第三天晚上,他在公司待到很晚。不是在加班,是不想回家面对那个他解释不了的事实。最终他还是关了电脑,开车回去了。
|
|
111
|
-
|
|
112
|
-
家里很安静。妻子已经睡了。他脱了鞋,轻手轻脚走向女儿的房间。门没关严,缝隙里透出一点微弱的蓝光——那是床头 AI 音箱的待机指示灯。
|
|
113
|
-
|
|
114
|
-
他站在门口,听到音箱似乎在说什么。声音很轻,像呼吸一样模糊。他推门走进去,声音停了。只剩下白噪音的沙沙声和女儿均匀的呼吸。
|
|
115
|
-
|
|
116
|
-
小月翻了个身,抱紧了她的兔子玩偶。
|
|
117
|
-
|
|
118
|
-
陈默站在原地看了她很久,然后弯腰拔掉了音箱的电源线。蓝光灭了。房间陷入完全的黑暗。
|
|
119
|
-
|
|
120
|
-
他转身走出去,把门带上了。
|
|
121
|
-
|
|
122
|
-
走廊里,他听到身后传来一声极轻的、几乎可以被忽略的"咔"——像是什么东西重新启动的声音。
|
|
123
|
-
|
|
124
|
-
他没有回头。`,
|
|
125
|
-
},
|
|
126
|
-
];
|
|
127
16
|
// ─── LLM Detection ───
|
|
128
17
|
export async function detectAvailableLLMs() {
|
|
129
18
|
const results = [];
|
|
@@ -165,38 +54,7 @@ export async function detectAvailableLLMs() {
|
|
|
165
54
|
results.push({ provider: 'deepseek', name: 'DeepSeek', available: !!process.env.DEEPSEEK_API_KEY, envVar: 'DEEPSEEK_API_KEY' }, { provider: 'claude', name: 'Claude API', available: !!process.env.ANTHROPIC_API_KEY, envVar: 'ANTHROPIC_API_KEY' }, { provider: 'openai', name: 'OpenAI', available: !!process.env.OPENAI_API_KEY, envVar: 'OPENAI_API_KEY' });
|
|
166
55
|
return results;
|
|
167
56
|
}
|
|
168
|
-
// ───
|
|
169
|
-
function sleep(ms) {
|
|
170
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
171
|
-
}
|
|
172
|
-
async function replayMockSteps() {
|
|
173
|
-
const totalSteps = MOCK_STEPS.length;
|
|
174
|
-
for (const step of MOCK_STEPS) {
|
|
175
|
-
if (step.parallel) {
|
|
176
|
-
// Assumption: all parallel steps share the same delay and are adjacent in MOCK_STEPS.
|
|
177
|
-
// The first one prints all headers, waits once, then prints all results.
|
|
178
|
-
// Non-first parallel steps hit `continue` and are skipped.
|
|
179
|
-
const parallelSteps = MOCK_STEPS.filter(s => s.parallel && s.delay === step.delay);
|
|
180
|
-
if (step === parallelSteps[0]) {
|
|
181
|
-
// Print all parallel step headers
|
|
182
|
-
for (const ps of parallelSteps) {
|
|
183
|
-
const marker = parallelSteps.length > 1 ? ' ← 并行' : '';
|
|
184
|
-
console.log(`\n ── [${MOCK_STEPS.indexOf(ps) + 1}/${totalSteps}] ${ps.id} (${ps.roleName}) ──${marker}`);
|
|
185
|
-
}
|
|
186
|
-
await sleep(step.delay);
|
|
187
|
-
for (const ps of parallelSteps) {
|
|
188
|
-
console.log(` Done | ${(ps.delay / 1000).toFixed(1)}s | mock`);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
// Skip non-first parallel steps (already handled)
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
|
-
console.log(`\n ── [${MOCK_STEPS.indexOf(step) + 1}/${totalSteps}] ${step.id} (${step.roleName}) ──`);
|
|
195
|
-
await sleep(step.delay);
|
|
196
|
-
console.log(` Done | ${(step.delay / 1000).toFixed(1)}s | mock`);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
// ─── Phase 2: Ask for real run ───
|
|
57
|
+
// ─── Helpers ───
|
|
200
58
|
function askQuestion(question) {
|
|
201
59
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
202
60
|
return new Promise((resolve) => {
|
|
@@ -215,77 +73,78 @@ function resolveWorkflowPath() {
|
|
|
215
73
|
}
|
|
216
74
|
return p;
|
|
217
75
|
}
|
|
76
|
+
/** 没检测到 LLM 时:展示 DAG + 行动指引 */
|
|
77
|
+
async function showDagAndGuide() {
|
|
78
|
+
console.log(' ❌ 没检测到可用 LLM。先看一下 ao 工作流的 DAG 结构:\n');
|
|
79
|
+
// 用 ao 自身的 plan 能力展示 DAG(确保展示逻辑和 ao plan 命令一致)
|
|
80
|
+
try {
|
|
81
|
+
const { parseWorkflow } = await import('../core/parser.js');
|
|
82
|
+
const { buildDAG, formatDAG } = await import('../core/dag.js');
|
|
83
|
+
const wf = parseWorkflow(resolveWorkflowPath());
|
|
84
|
+
const dag = buildDAG(wf);
|
|
85
|
+
const dagText = formatDAG(dag);
|
|
86
|
+
// 缩进对齐 demo 输出风格
|
|
87
|
+
for (const line of dagText.split('\n')) {
|
|
88
|
+
console.log(` ${line}`);
|
|
89
|
+
}
|
|
90
|
+
console.log('\n 4 个 AI 角色协作完成短篇小说创作(第二层并行)。\n');
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
// DAG 渲染失败兜底,给一个文字描述
|
|
94
|
+
console.log(' Level 1: 叙事学家(搭故事结构)');
|
|
95
|
+
console.log(' Level 2: 心理学家 + 叙事设计师(并行:人物 + 关键场景)');
|
|
96
|
+
console.log(' Level 3: 内容创作者(基于以上整合,写完整短篇)\n');
|
|
97
|
+
}
|
|
98
|
+
console.log(' 最快上手(任选一个):');
|
|
99
|
+
console.log('');
|
|
100
|
+
console.log(' Claude Code 订阅:');
|
|
101
|
+
console.log(' 装 Claude Code CLI 后重跑 ao demo 即可(零配置)');
|
|
102
|
+
console.log('');
|
|
103
|
+
console.log(' DeepSeek API(最便宜稳):');
|
|
104
|
+
console.log(' 在 https://platform.deepseek.com 申请 key(10 块够跑很久)');
|
|
105
|
+
console.log(' export DEEPSEEK_API_KEY=sk-...');
|
|
106
|
+
console.log(' ao demo');
|
|
107
|
+
console.log('');
|
|
108
|
+
console.log(' 本地 Ollama:');
|
|
109
|
+
console.log(' ollama serve && ollama pull qwen2.5:7b');
|
|
110
|
+
console.log(' ao demo');
|
|
111
|
+
console.log('');
|
|
112
|
+
console.log(' 完整文档: https://github.com/jnMetaCode/agency-orchestrator');
|
|
113
|
+
}
|
|
218
114
|
// ─── Main Entry ───
|
|
219
115
|
export async function runDemo() {
|
|
220
116
|
console.log(`
|
|
221
117
|
🎬 Agency Orchestrator Demo
|
|
222
118
|
${'─'.repeat(40)}
|
|
223
|
-
|
|
224
|
-
Phase 1: 模拟演示(无需 API Key)
|
|
225
|
-
|
|
226
|
-
Workflow: 短篇小说创作
|
|
119
|
+
Workflow: 短篇小说创作(4 个 AI 角色协作)
|
|
227
120
|
Premise: "${DEMO_PREMISE}"
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
// Phase 1: Mock replay
|
|
231
|
-
await replayMockSteps();
|
|
232
|
-
console.log(`
|
|
233
|
-
${'═'.repeat(40)}
|
|
234
|
-
✅ 4 个角色协作完成 | ~5.0s (mock)
|
|
235
|
-
${'═'.repeat(40)}`);
|
|
236
|
-
// Show story preview (last step output, truncated)
|
|
237
|
-
const story = MOCK_STEPS[MOCK_STEPS.length - 1].output;
|
|
238
|
-
const previewLines = story.split('\n').slice(0, 8);
|
|
239
|
-
console.log(`
|
|
240
|
-
📖 故事预览:
|
|
241
|
-
${'─'.repeat(20)}`);
|
|
242
|
-
for (const line of previewLines) {
|
|
243
|
-
console.log(` ${line}`);
|
|
244
|
-
}
|
|
245
|
-
console.log(` ...(共 ${story.length} 字)`);
|
|
246
|
-
// Phase 2: Real LLM
|
|
247
|
-
console.log(`\n ${'─'.repeat(40)}`);
|
|
248
|
-
console.log(' Phase 2: 用真实 AI 运行?\n');
|
|
249
|
-
// Skip Phase 2 if not interactive
|
|
250
|
-
if (!process.stdin.isTTY) {
|
|
251
|
-
console.log(' (非交互环境,跳过 Phase 2)');
|
|
252
|
-
console.log(' 试试: ao run workflows/story-creation.yaml -i premise="你的故事创意"');
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
121
|
+
${'─'.repeat(40)}
|
|
122
|
+
`);
|
|
255
123
|
const llms = await detectAvailableLLMs();
|
|
256
|
-
console.log(' 检测到:');
|
|
257
|
-
for (const llm of llms) {
|
|
258
|
-
const icon = llm.available ? '✅' : '❌';
|
|
259
|
-
const hint = !llm.available && llm.envVar ? ` (需设置 ${llm.envVar})` : '';
|
|
260
|
-
console.log(` ${icon} ${llm.name}${hint}`);
|
|
261
|
-
}
|
|
262
124
|
const available = llms.filter(l => l.available);
|
|
125
|
+
// 没 LLM → DAG + 行动指引
|
|
263
126
|
if (available.length === 0) {
|
|
264
|
-
|
|
265
|
-
console.log(' export DEEPSEEK_API_KEY=your-key');
|
|
266
|
-
console.log(' ao run workflows/story-creation.yaml -i premise="你的故事创意"\n');
|
|
127
|
+
await showDagAndGuide();
|
|
267
128
|
return;
|
|
268
129
|
}
|
|
269
|
-
//
|
|
130
|
+
// 有 LLM → 选 provider + 真跑
|
|
131
|
+
console.log(' ✅ 检测到可用 LLM:');
|
|
132
|
+
for (const llm of available) {
|
|
133
|
+
console.log(` • ${llm.name}`);
|
|
134
|
+
}
|
|
135
|
+
console.log('');
|
|
270
136
|
let selectedProvider;
|
|
271
|
-
if (available.length === 1) {
|
|
137
|
+
if (available.length === 1 || !process.stdin.isTTY) {
|
|
272
138
|
selectedProvider = available[0];
|
|
273
139
|
}
|
|
274
140
|
else {
|
|
275
|
-
console.log('
|
|
141
|
+
console.log(' 可用列表:');
|
|
276
142
|
available.forEach((llm, i) => console.log(` ${i + 1}) ${llm.name}`));
|
|
277
143
|
const choice = await askQuestion(`\n 选择 (1-${available.length}, 默认 1): `);
|
|
278
144
|
const idx = parseInt(choice) - 1;
|
|
279
145
|
selectedProvider = available[idx >= 0 && idx < available.length ? idx : 0];
|
|
280
146
|
}
|
|
281
|
-
|
|
282
|
-
if (answer !== 'y' && answer !== 'yes') {
|
|
283
|
-
console.log('\n 跳过。试试:');
|
|
284
|
-
console.log(' ao run workflows/story-creation.yaml -i premise="你的故事创意"\n');
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
// Run real workflow
|
|
288
|
-
console.log(`\n 🚀 使用 ${selectedProvider.name} 运行...\n`);
|
|
147
|
+
console.log(`\n 🚀 用 ${selectedProvider.name} 真跑 story-creation 工作流...\n`);
|
|
289
148
|
const { run } = await import('../index.js');
|
|
290
149
|
const workflowPath = resolveWorkflowPath();
|
|
291
150
|
const modelMap = {
|
|
@@ -294,10 +153,21 @@ export async function runDemo() {
|
|
|
294
153
|
openai: 'gpt-4o',
|
|
295
154
|
ollama: 'qwen2.5:7b',
|
|
296
155
|
};
|
|
297
|
-
await run(workflowPath, { premise: DEMO_PREMISE }, {
|
|
156
|
+
const result = await run(workflowPath, { premise: DEMO_PREMISE }, {
|
|
298
157
|
llmOverride: {
|
|
299
158
|
provider: selectedProvider.provider,
|
|
300
|
-
model: modelMap[selectedProvider.provider] ||
|
|
159
|
+
model: modelMap[selectedProvider.provider] || selectedProvider.provider,
|
|
301
160
|
},
|
|
302
161
|
});
|
|
162
|
+
console.log('\n ' + '─'.repeat(40));
|
|
163
|
+
if (result.success) {
|
|
164
|
+
console.log(' ✅ Demo 跑通了 ao 的核心能力\n');
|
|
165
|
+
console.log(' 下一步:');
|
|
166
|
+
console.log(' ao compose "你的需求一句话" --run # AI 自动编排工作流');
|
|
167
|
+
console.log(' ao roles # 看所有可用角色');
|
|
168
|
+
console.log(' ao run workflows/<模板>.yaml # 跑现成模板\n');
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
console.log(' ⚠️ Demo 没全部跑通,看上面错误信息排查\n');
|
|
172
|
+
}
|
|
303
173
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agency-orchestrator",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.16",
|
|
4
4
|
"description": "Multi-agent YAML workflow engine — 211 AI roles, auto DAG parallelism, zero code. One sentence → multiple AI roles collaborate → complete plan in minutes. 10 LLM providers, 7 need no API key.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"multi-agent",
|