Bug Description
Setting agent.planner_max_steps = 0 in config (which should mean "unlimited") still causes the planner to pause after 12 tool-call rounds with the error:
planner: paused after 12 tool-call rounds (agent.planner_max_steps) — the work so far is saved; send another message to continue, or set agent.planner_max_steps higher or to 0 for no limit
Environment
- Reasonix version: (please fill in, e.g., 0.47.x or git commit hash)
- Mode: CLI / Desktop / TUI (please specify)
- Config method: reasonix.toml / environment variable / CLI flag
Configuration
[agent]
planner_max_steps = 0 # should be unlimited
executor_max_steps = 0 # should be unlimited
Expected Behavior
With planner_max_steps = 0, the planner should be able to run unlimited tool-call rounds without hitting a step limit.
Actual Behavior
The planner pauses at exactly 12 rounds (the default value for planner_max_steps), as if the config setting of 0 is not being recognized.
Code Analysis
I traced the relevant code paths and found:
- Default value:
internal/config/config.go:994 — default is 12
- TOML decoding:
internal/config/config.go:665 — PlannerMaxSteps int \toml:"planner_max_steps"``
- Config to coordinator:
internal/boot/boot.go:860-862 — passes cfg.Agent.PlannerMaxSteps to agent.Options{MaxSteps: ...}
- Loop condition:
internal/agent/agent.go:539 — for step := 0; a.maxSteps <= 0 || step < a.maxSteps; step++
- Error generation:
internal/agent/agent.go:667 — returns the pause error when loop exits
- Existing test:
coordinator_test.go has TestCoordinatorPlannerMaxStepsZeroIsUnlimited confirming that MaxSteps=0 should be unlimited in unit tests
The code logic at line 539 (a.maxSteps <= 0 || step < a.maxSteps) correctly treats 0 as unlimited. However, the fact that the error fires at exactly 12 (the default) suggests the config value 0 is not being applied correctly — perhaps the TOML decode step is not overwriting the default when the value is 0.
Possible Root Cause
When using toml.DecodeFile(path, cfg) into a struct already initialized with defaults (via Default()), if the TOML library treats 0 as an omitted/unset value, it may not overwrite the existing default field value. Alternatively, there might be a merge/override issue in the configuration loading chain.
Steps to Reproduce
- Set
planner_max_steps = 0 in reasonix.toml
- Start a coding session where the planner needs more than 12 read-only tool calls
- Observe the planner pausing after 12 rounds with the error message above
Suggested Fix
- Verify that
toml.DecodeFile correctly overwrites PlannerMaxSteps from 12 (default) to 0 when the config file explicitly sets planner_max_steps = 0
- Consider adding an end-to-end test that loads a config with
planner_max_steps = 0 and verifies the planner loop runs beyond 12 rounds
Bug Description
Setting
agent.planner_max_steps = 0in config (which should mean "unlimited") still causes the planner to pause after 12 tool-call rounds with the error:Environment
Configuration
Expected Behavior
With
planner_max_steps = 0, the planner should be able to run unlimited tool-call rounds without hitting a step limit.Actual Behavior
The planner pauses at exactly 12 rounds (the default value for
planner_max_steps), as if the config setting of0is not being recognized.Code Analysis
I traced the relevant code paths and found:
internal/config/config.go:994— default is 12internal/config/config.go:665—PlannerMaxSteps int \toml:"planner_max_steps"``internal/boot/boot.go:860-862— passescfg.Agent.PlannerMaxStepstoagent.Options{MaxSteps: ...}internal/agent/agent.go:539—for step := 0; a.maxSteps <= 0 || step < a.maxSteps; step++internal/agent/agent.go:667— returns the pause error when loop exitscoordinator_test.gohasTestCoordinatorPlannerMaxStepsZeroIsUnlimitedconfirming thatMaxSteps=0should be unlimited in unit testsThe code logic at line 539 (
a.maxSteps <= 0 || step < a.maxSteps) correctly treats 0 as unlimited. However, the fact that the error fires at exactly 12 (the default) suggests the config value0is not being applied correctly — perhaps the TOML decode step is not overwriting the default when the value is0.Possible Root Cause
When using
toml.DecodeFile(path, cfg)into a struct already initialized with defaults (viaDefault()), if the TOML library treats0as an omitted/unset value, it may not overwrite the existing default field value. Alternatively, there might be a merge/override issue in the configuration loading chain.Steps to Reproduce
planner_max_steps = 0inreasonix.tomlSuggested Fix
toml.DecodeFilecorrectly overwritesPlannerMaxStepsfrom 12 (default) to 0 when the config file explicitly setsplanner_max_steps = 0planner_max_steps = 0and verifies the planner loop runs beyond 12 rounds