feat: remove default step limit
Agent loop now runs unlimited by default. The model decides when to stop. --max-steps is still available as an optional safety cap.
- commit
- b2fa0e3a2fd043103dbc3410cea8edd1337ed19d
- author
- patriceckhart · · 2026-04-26 11:32 UTC
- parent
- e52a560
- signature
- unsigned
- refs
- tag: v0.1.21
3 files · +10 -10
M internal/agent/args.go +2 -2
| @@ -89,7 +89,7 @@ type Args struct { | |||
| 89 | 89 | ||
| 90 | 90 | // ParseArgs parses the process arguments (excluding argv[0]). | |
| 91 | 91 | func ParseArgs(in []string) (Args, error) { | |
| 92 | - | a := Args{Mode: ModeInteractive, MaxSteps: 50} | |
| 92 | + | a := Args{Mode: ModeInteractive, MaxSteps: 0} | |
| 93 | 93 | positional := []string{} | |
| 94 | 94 | ||
| 95 | 95 | want := func(i *int, flag string) (string, error) { | |
| @@ -352,7 +352,7 @@ func PrintHelp(version string) { | |||
| 352 | 352 | row{"--with-skills", "load user-installed skills in addition to built-ins"}, | |
| 353 | 353 | ) | |
| 354 | 354 | section("misc", | |
| 355 | - | row{"--max-steps N", "agent loop iteration cap (default 50)"}, | |
| 355 | + | row{"--max-steps N", "agent loop iteration cap (default: unlimited)"}, | |
| 356 | 356 | row{"--list-models", "print known models and exit"}, | |
| 357 | 357 | row{"-h, --help", "show this help"}, | |
| 358 | 358 | row{"-v, --version", "show version info"}, | |
| @@ -89,7 +89,7 @@ type Args struct { | |||||
| 89 | 89 | ||||
| 90 | // ParseArgs parses the process arguments (excluding argv[0]). | 90 | // ParseArgs parses the process arguments (excluding argv[0]). | ||
| 91 | func ParseArgs(in []string) (Args, error) { | 91 | func ParseArgs(in []string) (Args, error) { | ||
| 92 | - | a := Args{Mode: ModeInteractive, MaxSteps: 50} | 92 | + | a := Args{Mode: ModeInteractive, MaxSteps: 0} |
| 93 | positional := []string{} | 93 | positional := []string{} | ||
| 94 | 94 | ||||
| 95 | want := func(i *int, flag string) (string, error) { | 95 | want := func(i *int, flag string) (string, error) { | ||
| @@ -352,7 +352,7 @@ func PrintHelp(version string) { | |||||
| 352 | row{"--with-skills", "load user-installed skills in addition to built-ins"}, | 352 | row{"--with-skills", "load user-installed skills in addition to built-ins"}, | ||
| 353 | ) | 353 | ) | ||
| 354 | section("misc", | 354 | section("misc", | ||
| 355 | - | row{"--max-steps N", "agent loop iteration cap (default 50)"}, | 355 | + | row{"--max-steps N", "agent loop iteration cap (default: unlimited)"}, |
| 356 | row{"--list-models", "print known models and exit"}, | 356 | row{"--list-models", "print known models and exit"}, | ||
| 357 | row{"-h, --help", "show this help"}, | 357 | row{"-h, --help", "show this help"}, | ||
| 358 | row{"-v, --version", "show version info"}, | 358 | row{"-v, --version", "show version info"}, | ||
M internal/agent/build.go +1 -4
| @@ -285,10 +285,7 @@ func Resolve(args Args, requireCred bool) (Resolved, error) { | |||
| 285 | 285 | ||
| 286 | 286 | reasoning := firstNonEmpty(args.Reasoning, cfg.Reasoning) | |
| 287 | 287 | ||
| 288 | - | max := args.MaxSteps | |
| 289 | - | if max <= 0 { | |
| 290 | - | max = 50 | |
| 291 | - | } | |
| 288 | + | max := args.MaxSteps // 0 = unlimited | |
| 292 | 289 | ||
| 293 | 290 | return Resolved{ | |
| 294 | 291 | Provider: provName, | |
| @@ -285,10 +285,7 @@ func Resolve(args Args, requireCred bool) (Resolved, error) { | |||||
| 285 | 285 | ||||
| 286 | reasoning := firstNonEmpty(args.Reasoning, cfg.Reasoning) | 286 | reasoning := firstNonEmpty(args.Reasoning, cfg.Reasoning) | ||
| 287 | 287 | ||||
| 288 | - | max := args.MaxSteps | 288 | + | max := args.MaxSteps // 0 = unlimited |
| 289 | - | if max <= 0 { | |||
| 290 | - | max = 50 | |||
| 291 | - | } | |||
| 292 | 289 | ||||
| 293 | return Resolved{ | 290 | return Resolved{ | ||
| 294 | Provider: provName, | 291 | Provider: provName, | ||
M internal/core/agent.go +7 -4
| @@ -63,7 +63,7 @@ func NewAgent(client provider.Client, model, system string, tools Registry) *Age | |||
| 63 | 63 | Model: model, | |
| 64 | 64 | System: system, | |
| 65 | 65 | Tools: tools, | |
| 66 | - | MaxSteps: 50, | |
| 66 | + | MaxSteps: 0, // 0 = unlimited | |
| 67 | 67 | } | |
| 68 | 68 | } | |
| 69 | 69 | ||
| @@ -158,7 +158,7 @@ func (a *Agent) wrapSink(sink func(AgentEvent)) func(AgentEvent) { | |||
| 158 | 158 | } | |
| 159 | 159 | ||
| 160 | 160 | func (a *Agent) runLoop(ctx context.Context, sink func(AgentEvent)) error { | |
| 161 | - | for step := 1; step <= a.MaxSteps; step++ { | |
| 161 | + | for step := 1; a.MaxSteps <= 0 || step <= a.MaxSteps; step++ { | |
| 162 | 162 | sink(EvTurnStart{Step: step}) | |
| 163 | 163 | if a.BeforeTurn != nil { | |
| 164 | 164 | if allowed, reason := a.BeforeTurn(step); !allowed { | |
| @@ -207,8 +207,11 @@ func (a *Agent) runLoop(ctx context.Context, sink func(AgentEvent)) error { | |||
| 207 | 207 | sink(EvDone{}) | |
| 208 | 208 | return nil | |
| 209 | 209 | } | |
| 210 | - | sink(EvDone{}) | |
| 211 | - | return fmt.Errorf("max steps (%d) exceeded", a.MaxSteps) | |
| 210 | + | if a.MaxSteps > 0 { | |
| 211 | + | sink(EvDone{}) | |
| 212 | + | return fmt.Errorf("max steps (%d) exceeded", a.MaxSteps) | |
| 213 | + | } | |
| 214 | + | return nil | |
| 212 | 215 | } | |
| 213 | 216 | ||
| 214 | 217 | // oneTurn calls the LLM once, forwards events, returns the stop reason | |
| @@ -63,7 +63,7 @@ func NewAgent(client provider.Client, model, system string, tools Registry) *Age | |||||
| 63 | Model: model, | 63 | Model: model, | ||
| 64 | System: system, | 64 | System: system, | ||
| 65 | Tools: tools, | 65 | Tools: tools, | ||
| 66 | - | MaxSteps: 50, | 66 | + | MaxSteps: 0, // 0 = unlimited |
| 67 | } | 67 | } | ||
| 68 | } | 68 | } | ||
| 69 | 69 | ||||
| @@ -158,7 +158,7 @@ func (a *Agent) wrapSink(sink func(AgentEvent)) func(AgentEvent) { | |||||
| 158 | } | 158 | } | ||
| 159 | 159 | ||||
| 160 | func (a *Agent) runLoop(ctx context.Context, sink func(AgentEvent)) error { | 160 | func (a *Agent) runLoop(ctx context.Context, sink func(AgentEvent)) error { | ||
| 161 | - | for step := 1; step <= a.MaxSteps; step++ { | 161 | + | for step := 1; a.MaxSteps <= 0 || step <= a.MaxSteps; step++ { |
| 162 | sink(EvTurnStart{Step: step}) | 162 | sink(EvTurnStart{Step: step}) | ||
| 163 | if a.BeforeTurn != nil { | 163 | if a.BeforeTurn != nil { | ||
| 164 | if allowed, reason := a.BeforeTurn(step); !allowed { | 164 | if allowed, reason := a.BeforeTurn(step); !allowed { | ||
| @@ -207,8 +207,11 @@ func (a *Agent) runLoop(ctx context.Context, sink func(AgentEvent)) error { | |||||
| 207 | sink(EvDone{}) | 207 | sink(EvDone{}) | ||
| 208 | return nil | 208 | return nil | ||
| 209 | } | 209 | } | ||
| 210 | - | sink(EvDone{}) | 210 | + | if a.MaxSteps > 0 { |
| 211 | - | return fmt.Errorf("max steps (%d) exceeded", a.MaxSteps) | 211 | + | sink(EvDone{}) |
| 212 | + | return fmt.Errorf("max steps (%d) exceeded", a.MaxSteps) | |||
| 213 | + | } | |||
| 214 | + | return nil | |||
| 212 | } | 215 | } | ||
| 213 | 216 | ||||
| 214 | // oneTurn calls the LLM once, forwards events, returns the stop reason | 217 | // oneTurn calls the LLM once, forwards events, returns the stop reason | ||