Bug: parallel strategy reduce block fails with "unknown step type"
Summary
When submitting a workflow with "strategy": "parallel" + a reduce block via POST /runs, the request fails validation with {"error":{"code":"bad_request","message":"unknown step type"}}.
Root cause
src/strategy.zig:184 wraps the user-supplied reduce block as a synthetic step with type: "reduce":
// Set type to reduce
try new_obj.put(allocator, "type", std.json.Value{ .string = "reduce" });
But StepType in src/types.zig:49-56 does not include reduce:
pub const StepType = enum {
task,
route,
interrupt,
agent,
send,
transform,
subgraph,
// ... no `reduce`
};
After strategy expansion, validateStepsForCreateRun (src/workflow_validation.zig:66) rejects the synthetic reduce step:
if (types.StepType.fromString(step_type) == null) return error.StepTypeUnknown;
The expanded steps are then surfaced to api.zig:1992 → HTTP 400 "unknown step type".
Reproduction
Stock main branch (81d1a20). Submit:
curl -X POST http://localhost:7720/runs \
-H "Content-Type: application/json" \
-d '{
"strategy": "parallel",
"steps": [
{"id":"a","type":"task","worker_tags":["default"],"prompt_template":"research A","timeout_ms":30000},
{"id":"b","type":"task","worker_tags":["default"],"prompt_template":"research B","timeout_ms":30000}
],
"reduce": {
"id": "synth",
"worker_tags": ["default"],
"prompt_template": "synthesize: {{steps.a.output}} {{steps.b.output}}"
}
}'
Response: {"error":{"code":"bad_request","message":"unknown step type"}}
Expected
Reduce block is a documented feature in examples/multi-agent-slack/workflows/parallel-research.json and in the README's Workflow Graph Features section. Should expand to a valid step type and execute after all parallel steps complete.
Actual
Validation rejects the synthetic reduce step before the run starts.
Workaround
Drop strategy: "parallel" and use manual depends_on for the join:
{
"steps": [
{"id":"a","type":"task","output_key":"a_out","worker_tags":["default"],"prompt_template":"...","timeout_ms":30000},
{"id":"b","type":"task","output_key":"b_out","worker_tags":["default"],"prompt_template":"...","timeout_ms":30000},
{"id":"synth","type":"task","output_key":"final","worker_tags":["default"],"depends_on":["a","b"],"prompt_template":"... {{state.a_out}} {{state.b_out}} ...","timeout_ms":30000}
]
}
This works (verified on local-deploy fork c0e3648). Outputs chain via state.<output_key> template vars.
Two possible fixes
Option A (minimal): Add reduce to StepType enum. Reduces are already handled in engine.zig (reducer logic), so type recognition alone should unblock validation.
Option B (cleaner): Use transform or task as the synthetic type for reduce (since reduces are essentially a transform with implicit deps). Update strategy.zig:184 to emit type: "task" or type: "transform". This avoids bloating the enum with a strategy-specific concept.
Environment
- nullboiler commit:
81d1a20 (main), also confirmed on fork local-deploy c0e3648
- Zig 0.16.0
- Discovered while running 4-node vector DB comparison workflow (3 parallel research + 1 reduce synthesis)
Related
- The legacy
multi-agent-slack examples use {{steps.X.output}} template syntax that doesn't work in the new graph engine (which uses {{state.X}} with per-step output_key). Worth a separate doc/examples cleanup.
Bug: parallel strategy
reduceblock fails with "unknown step type"Summary
When submitting a workflow with
"strategy": "parallel"+ areduceblock viaPOST /runs, the request fails validation with{"error":{"code":"bad_request","message":"unknown step type"}}.Root cause
src/strategy.zig:184wraps the user-suppliedreduceblock as a synthetic step withtype: "reduce":But
StepTypeinsrc/types.zig:49-56does not includereduce:After strategy expansion,
validateStepsForCreateRun(src/workflow_validation.zig:66) rejects the synthetic reduce step:The expanded steps are then surfaced to
api.zig:1992→ HTTP 400"unknown step type".Reproduction
Stock main branch (
81d1a20). Submit:Response:
{"error":{"code":"bad_request","message":"unknown step type"}}Expected
Reduce block is a documented feature in
examples/multi-agent-slack/workflows/parallel-research.jsonand in the README's Workflow Graph Features section. Should expand to a valid step type and execute after all parallel steps complete.Actual
Validation rejects the synthetic reduce step before the run starts.
Workaround
Drop
strategy: "parallel"and use manualdepends_onfor the join:{ "steps": [ {"id":"a","type":"task","output_key":"a_out","worker_tags":["default"],"prompt_template":"...","timeout_ms":30000}, {"id":"b","type":"task","output_key":"b_out","worker_tags":["default"],"prompt_template":"...","timeout_ms":30000}, {"id":"synth","type":"task","output_key":"final","worker_tags":["default"],"depends_on":["a","b"],"prompt_template":"... {{state.a_out}} {{state.b_out}} ...","timeout_ms":30000} ] }This works (verified on local-deploy fork
c0e3648). Outputs chain viastate.<output_key>template vars.Two possible fixes
Option A (minimal): Add
reducetoStepTypeenum. Reduces are already handled in engine.zig (reducer logic), so type recognition alone should unblock validation.Option B (cleaner): Use
transformortaskas the synthetic type for reduce (since reduces are essentially a transform with implicit deps). Updatestrategy.zig:184to emittype: "task"ortype: "transform". This avoids bloating the enum with a strategy-specific concept.Environment
81d1a20(main), also confirmed on forklocal-deployc0e3648Related
multi-agent-slackexamples use{{steps.X.output}}template syntax that doesn't work in the new graph engine (which uses{{state.X}}with per-stepoutput_key). Worth a separate doc/examples cleanup.