detached b2fa0e3

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 {
8989
9090 // ParseArgs parses the process arguments (excluding argv[0]).
9191 func ParseArgs(in []string) (Args, error) {
92- a := Args{Mode: ModeInteractive, MaxSteps: 50}
92+ a := Args{Mode: ModeInteractive, MaxSteps: 0}
9393 positional := []string{}
9494
9595 want := func(i *int, flag string) (string, error) {
@@ -352,7 +352,7 @@ func PrintHelp(version string) {
352352 row{"--with-skills", "load user-installed skills in addition to built-ins"},
353353 )
354354 section("misc",
355- row{"--max-steps N", "agent loop iteration cap (default 50)"},
355+ row{"--max-steps N", "agent loop iteration cap (default: unlimited)"},
356356 row{"--list-models", "print known models and exit"},
357357 row{"-h, --help", "show this help"},
358358 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) {
285285
286286 reasoning := firstNonEmpty(args.Reasoning, cfg.Reasoning)
287287
288- max := args.MaxSteps
289- if max <= 0 {
290- max = 50
291- }
288+ max := args.MaxSteps // 0 = unlimited
292289
293290 return Resolved{
294291 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.MaxSteps288+ 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
6363 Model: model,
6464 System: system,
6565 Tools: tools,
66- MaxSteps: 50,
66+ MaxSteps: 0, // 0 = unlimited
6767 }
6868 }
6969
@@ -158,7 +158,7 @@ func (a *Agent) wrapSink(sink func(AgentEvent)) func(AgentEvent) {
158158 }
159159
160160 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++ {
162162 sink(EvTurnStart{Step: step})
163163 if a.BeforeTurn != nil {
164164 if allowed, reason := a.BeforeTurn(step); !allowed {
@@ -207,8 +207,11 @@ func (a *Agent) runLoop(ctx context.Context, sink func(AgentEvent)) error {
207207 sink(EvDone{})
208208 return nil
209209 }
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
212215 }
213216
214217 // 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 nil208 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 reason217 // oneTurn calls the LLM once, forwards events, returns the stop reason

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 476

↑↓ moveenter openesc close