agency-orchestrator 0.6.11 → 0.6.13

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.
@@ -5,7 +5,8 @@
5
5
  * 安装: curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash
6
6
  * 文档: https://hermes-agent.nousresearch.com/
7
7
  *
8
- * 使用 hermes chat -q "prompt" 的单次查询模式(非交互式)
8
+ * 使用 hermes -z "prompt" 的 oneshot 模式(非交互式)
9
+ * 旧版 hermes chat -q 已废弃,详见 issue #14
9
10
  * 支持 --model 指定模型(如 anthropic/claude-sonnet-4、openai/gpt-4o 等)
10
11
  */
11
12
  import { CLIBaseConnector } from './cli-base.js';
@@ -5,7 +5,8 @@
5
5
  * 安装: curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash
6
6
  * 文档: https://hermes-agent.nousresearch.com/
7
7
  *
8
- * 使用 hermes chat -q "prompt" 的单次查询模式(非交互式)
8
+ * 使用 hermes -z "prompt" 的 oneshot 模式(非交互式)
9
+ * 旧版 hermes chat -q 已废弃,详见 issue #14
9
10
  * 支持 --model 指定模型(如 anthropic/claude-sonnet-4、openai/gpt-4o 等)
10
11
  */
11
12
  import { CLIBaseConnector } from './cli-base.js';
@@ -16,7 +17,7 @@ export class HermesCLIConnector extends CLIBaseConnector {
16
17
  displayName: 'Hermes Agent CLI',
17
18
  installHint: 'curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash',
18
19
  buildArgs: (prompt, config) => {
19
- const args = ['chat', '-q', prompt];
20
+ const args = ['-z', prompt];
20
21
  if (config.model) {
21
22
  args.push('--model', config.model);
22
23
  }
@@ -62,6 +62,55 @@ export function parseWorkflow(filePath) {
62
62
  export function validateWorkflow(workflow) {
63
63
  const errors = [];
64
64
  const stepIds = new Set(workflow.steps.map(s => s.id));
65
+ const stepById = new Map(workflow.steps.map(s => [s.id, s]));
66
+ // step.output 唯一性检查:两个 step 不能 output 到同一个变量名
67
+ // 否则下游引用拿到的值取决于 context Map 的写入顺序,不可预期
68
+ //
69
+ // 两类合法例外不报错:
70
+ // 1. any_completed 分支收敛:下游用 depends_on_mode: any_completed 引用这些
71
+ // 重名 step(任一分支完成即走,重名 output 是有意设计)
72
+ // 2. loop 迭代覆盖:重名 step 中有任一个带 loop 字段(种子 step + loop step
73
+ // 反复覆盖同名 output,是常见的"原地修改"迭代模式,如 write/revise/brand_review 链)
74
+ const outputToSteps = new Map();
75
+ for (const step of workflow.steps) {
76
+ if (!step.output)
77
+ continue;
78
+ const owners = outputToSteps.get(step.output) || [];
79
+ owners.push(step.id);
80
+ outputToSteps.set(step.output, owners);
81
+ }
82
+ for (const [outName, owners] of outputToSteps) {
83
+ if (owners.length <= 1)
84
+ continue;
85
+ const ownerSet = new Set(owners);
86
+ const hasAnyCompletedConsumer = workflow.steps.some(s => s.depends_on_mode === 'any_completed'
87
+ && s.depends_on?.some(d => ownerSet.has(d)));
88
+ if (hasAnyCompletedConsumer)
89
+ continue;
90
+ const hasLoopOwner = owners.some(id => stepById.get(id)?.loop);
91
+ if (hasLoopOwner)
92
+ continue;
93
+ errors.push(`output 变量 "${outName}" 被多个 step 同时产出: ${owners.join(', ')}(重名会让下游引用结果不确定)`);
94
+ }
95
+ // 计算每个 step 的 DAG 上游 step ids(递归 depends_on 闭包,不含自身)。
96
+ // 用于校验"变量必须来自 inputs 或当前 step 的上游"——和 autoFix 的拓扑约束保持一致
97
+ function upstreamStepIds(stepId) {
98
+ const out = new Set();
99
+ const stack = [stepId];
100
+ while (stack.length > 0) {
101
+ const cur = stack.pop();
102
+ const step = stepById.get(cur);
103
+ if (!step)
104
+ continue;
105
+ for (const dep of step.depends_on || []) {
106
+ if (out.has(dep))
107
+ continue;
108
+ out.add(dep);
109
+ stack.push(dep);
110
+ }
111
+ }
112
+ return out;
113
+ }
65
114
  for (const step of workflow.steps) {
66
115
  // 检查 depends_on 引用
67
116
  if (step.depends_on) {
@@ -92,17 +141,55 @@ export function validateWorkflow(workflow) {
92
141
  errors.push(`step "${step.id}" 的 loop 缺少 exit_condition`);
93
142
  }
94
143
  }
95
- // 检查 {{变量}} 引用
96
- const varRefs = step.task?.match(/\{\{(\w+)\}\}/g) || [];
144
+ // 检查 {{变量}} 引用:必须来自 inputs,或来自当前 step 的 DAG 上游 step.output
145
+ // (之前只检查"任意 step 是否产出该变量",让"早期 step 引用下游 output"这种
146
+ // 拓扑反向错误漏过 validate,到 run 阶段才崩。和 autoFix 的拓扑约束对齐)
147
+ // 范围: step.task / step.condition / step.loop.exit_condition / step.prompt
148
+ const refTexts = [];
149
+ if (step.task)
150
+ refTexts.push(step.task);
151
+ if (step.condition)
152
+ refTexts.push(step.condition);
153
+ if (step.loop?.exit_condition)
154
+ refTexts.push(step.loop.exit_condition);
155
+ if (step.prompt)
156
+ refTexts.push(step.prompt);
157
+ const varRefs = [];
158
+ for (const text of refTexts) {
159
+ const matches = text.match(/\{\{(\w+)\}\}/g) || [];
160
+ varRefs.push(...matches);
161
+ }
162
+ if (varRefs.length === 0)
163
+ continue;
164
+ const upStepIds = upstreamStepIds(step.id);
165
+ const upstreamOutputs = new Set();
166
+ for (const id of upStepIds) {
167
+ const s = stepById.get(id);
168
+ if (s?.output)
169
+ upstreamOutputs.add(s.output);
170
+ }
171
+ const reportedVars = new Set(); // 同 step 内同名变量只报一次
97
172
  for (const ref of varRefs) {
98
173
  const varName = ref.slice(2, -2);
99
- // 变量要么来自 inputs,要么来自某个 step 的 output
174
+ if (varName === '_loop_iteration')
175
+ continue;
176
+ if (reportedVars.has(varName))
177
+ continue;
100
178
  const inputDef = workflow.inputs?.find(i => i.name === varName);
101
- const isOutput = workflow.steps.some(s => s.output === varName);
102
- if (!inputDef && !isOutput && varName !== '_loop_iteration') {
179
+ if (inputDef)
180
+ continue;
181
+ if (upstreamOutputs.has(varName))
182
+ continue;
183
+ // 不在 inputs 也不在上游 outputs:错误
184
+ // 区分两种错误信息,方便 autoFix / repairWithLLM 处理
185
+ const producedBySomeStep = workflow.steps.some(s => s.output === varName);
186
+ if (producedBySomeStep) {
187
+ errors.push(`step "${step.id}" 引用了未定义的变量: {{${varName}}} (该变量由非上游 step 产出,需要把对应 step 加进 depends_on)`);
188
+ }
189
+ else {
103
190
  errors.push(`step "${step.id}" 引用了未定义的变量: {{${varName}}}`);
104
191
  }
105
- // 可选输入无默认值时,运行时自动填空字符串 — 非错误,不再警告
192
+ reportedVars.add(varName);
106
193
  }
107
194
  }
108
195
  // 检查循环依赖
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agency-orchestrator",
3
- "version": "0.6.11",
3
+ "version": "0.6.13",
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",
@@ -87,7 +87,7 @@ steps:
87
87
 
88
88
  每条风险明确标「发生概率」(高/中/低)。
89
89
  output: risk
90
- depends_on: [research]
90
+ depends_on: [research, financial]
91
91
 
92
92
  - id: cfo_opinion
93
93
  role: "finance/finance-financial-forecaster"
@@ -97,7 +97,7 @@ steps:
97
97
 
98
98
  ⚠️ 所有法条引用不确定处必须明确标「需核实最新法规」。
99
99
  output: risk_analysis
100
- depends_on: [intake]
100
+ depends_on: [intake, document_review]
101
101
 
102
102
  - id: opinion
103
103
  role: "legal/legal-policy-writer"
@@ -81,7 +81,7 @@ steps:
81
81
 
82
82
  风格参考:小红书当前热门的视觉趋势。
83
83
  output: visual_plan
84
- depends_on: [topic_planning]
84
+ depends_on: [topic_planning, write_notes]
85
85
 
86
86
  - id: optimize
87
87
  role: "marketing/marketing-xiaohongshu-operator"