fix(strategy): expand reduce block to a task step - #39
Open
raskevichai wants to merge 1 commit into
Open
Conversation
buildReduceStep set the synthetic step's type to "reduce", but StepType has no such variant, so validateStepsForCreateRun rejected every parallel run carrying a reduce block with HTTP 400 "unknown step type". No node handler anywhere reads a "reduce" type - the engine dispatches task/agent, route, interrupt, transform, subgraph and send - so adding the variant to the enum would only move the failure from validation to dispatch. A reduce block carries worker_tags and a prompt_template and is joined to its inputs by the depends_on edges buildReduceStep already builds, which is exactly a task. Closes nullclaw#33.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #33.
Root cause
buildReduceStep(src/strategy.zig) sets the synthetic step's type to"reduce":StepType(src/types.zig) has seven variants -task,route,interrupt,agent,send,transform,subgraph- and none of them isreduce.validateStepsForCreateRunruns on the expanded steps, so everyPOST /runscarryingstrategy: "parallel"plus areduceblock is rejected with400 {"code":"bad_request","message":"unknown step type"}before the run is created. The reduce block is documented in the README and used byexamples/multi-agent-slack/workflows/parallel-research.json, so the documented path never worked.Why
taskand not a new enum variantThe issue lists two options. This PR takes the second.
Adding
reducetoStepTypeonly moves the failure: the engine's node dispatch (engine.zig) branches onroute,interrupt,transform,task/agent,subgraphandsend, and there is no handler that reads areducetype anywhere insrc/. The only other occurrences of the word are state reducers, which are an unrelated concept. A run would pass validation and then fall through dispatch.A reduce block carries
worker_tagsand aprompt_template, and its join is already expressed by thedepends_onarraybuildReduceStepbuilds over every sibling step. That is exactly a task, so the synthetic type is nowtaskand the fan-in stays where it belongs - in the edges, not in the type.Changes
src/strategy.zig- the emitted type moves to a namedreduce_step_typeconstant so the reason it is not"reduce"is recorded next to the decision. Nothing else in the expansion changes; the copied user fields, the default__reduceid and thedepends_onconstruction are untouched.Tests
Three added, two updated.
Added:
API: create run accepts parallel strategy with reduce block- drives the issue's payload throughhandleRequestand expects 201. This is the reported defect end to end.expandStrategy: reduce step type is a known StepType- asserts every expanded step resolves throughStepType.fromString, so a future synthetic type that the enum does not know fails here rather than at an HTTP boundary.expandStrategy: reduce step preserves user fields-prompt_template,output_keyandworker_tagssurvive the type rewrite.Updated: the two existing reduce tests asserted the
"reduce"type string and now assert"task".Sanity check: restoring
"reduce"makes all four reduce tests fail, the API one withexpected 201, found 400- the exact response from the issue.Verification
The e2e suite (
tests/test_e2e.sh) was not run; it needs Python mock workers and a live server. The change is covered at the API layer instead.Scope
Not included:
sequentialdoes not enforce chain order) shares a root cause with BUG: strategy expansion discarded — raw body stored instead of expanded workflow (P0) #36 and is addressed by fix(api): persist strategy-expanded steps as the run workflow #38, not here.{{steps.X.output}}template syntax in the legacymulti-agent-slackexamples still does not resolve under the graph engine, which uses{{state.X}}with a per-stepoutput_key. That is a docs/examples fix.One related defect found while confirming the above, left for a separate change because a rename does not fix it:
expandStepNestedemitstype: "sub_workflow"for a step that carries bothstrategyandsteps, andsub_workflowis not inStepTypeeither, so nested strategies fail validation with the same "unknown step type". Retyping it tosubgraphis not sufficient - the engine's subgraph node resolves a stored workflow byworkflow_id, while the expansion builds an inlineworkflowobject, so it would then fail at dispatch with "subgraph missing workflow_id". Making nested strategies work needs a decision on whether to persist the inline workflow and reference its id, or to teach the subgraph node to accept an inline definition.