Skip to content

feat: add max_turns to recipe and subagent settings#6687

Merged
katzdave merged 1 commit intoblock:mainfrom
jhult:feat/6198
Jan 28, 2026
Merged

feat: add max_turns to recipe and subagent settings#6687
katzdave merged 1 commit intoblock:mainfrom
jhult:feat/6198

Conversation

@jhult
Copy link
Contributor

@jhult jhult commented Jan 24, 2026

Summary

Implements the max_turns feature request from #6198. The feature allows controlling the maximum number of turns for subagents at multiple levels.

All tests pass (541 tests), build succeeds, code formatted.

Implementation Details

Priority Order (highest to lowest)

  1. Subagent tool override (settings.max_turns in tool call)
  2. Recipe settings (settings.max_turns in recipe yaml)
  3. Environment variable (GOOSE_SUBAGENT_MAX_TURNS)
  4. Default value (25)

Documentation

  • Updated recipe-reference.md with max_turns setting
  • Updated environment-variables.md with override behavior
  • Updated subagents.mdx with configuration examples

Type of Change

  • Feature
  • Bug fix
  • Refactor / Code quality
  • Performance improvement
  • Documentation
  • Tests
  • Security fix
  • Build / Release
  • Other (specify below)

AI Assistance

  • This PR was created or reviewed with AI assistance

Testing

The existing subagent_tool_tests.rs tests focus on tool creation and schema validation, not runtime behavior. Testing the actual max_turns behavior at runtime would require:

  • Creating a subagent that runs multiple turns
  • Setting a low max_turns limit
  • Verifying it stops at that limit

This is more of an end-to-end test. Given the complexity and that we already have good coverage of the mechanics (constants, env var behavior, JSON schema), I think the current test coverage is reasonable. The real validation would happen in manual testing or as a separate end-to-end test suite.

Related Issues

Implements #6198

@jhult jhult requested a review from a team as a code owner January 24, 2026 01:38
@blackgirlbytes
Copy link
Contributor

hi thanks for fixing!!! For the doc changes, could you kindly remove those? Only because your changes won't be released automatically...and the docs will be ahead of the release.

@jhult
Copy link
Contributor Author

jhult commented Jan 24, 2026

@blackgirlbytes, documentation updates have been removed.

Copy link
Collaborator

@katzdave katzdave left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

.and_then(|r| r.settings.as_ref())
.and_then(|s| s.max_turns);

let task_config = TaskConfig::with_max_turns(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically this with_ pattern is used for chaining rather than a new constructor.

So I'd go something like:

TaskConfig::new(...).with_max_turns(max_turns_from_recipe)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

extensions: Vec<ExtensionConfig>,
max_turns_override: Option<usize>,
) -> Self {
let max_turns = max_turns_override.or_else(|| {
Copy link
Collaborator

@katzdave katzdave Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can leave this default case in the constructor as before.

with_max_turns can be something like:

  pub fn with_max_turns(mut self, max_turns: Option<usize>) -> Self {
      if let Some(turns) = max_turns {
          self.max_turns = Some(turns);
      }
      self
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

params: &SubagentParams,
) -> Result<TaskConfig> {
if let Some(settings) = &params.settings {
// Apply max_turns override if provided
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rm comment

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

let task_config =
TaskConfig::new(provider, &session.id, &session.working_dir, extensions);

// Extract max_turns from recipe settings if available
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rm comment

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Collaborator

@katzdave katzdave left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

}
}

// Note: The actual TaskConfig behavior is tested in crates/goose/tests/agent.rs
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Implements block#6198

Signed-off-by: Jonathan Hult <Jonathan@JonathanHult.com>
@katzdave
Copy link
Collaborator

merging!

@katzdave katzdave merged commit b8810be into block:main Jan 28, 2026
18 checks passed
eliasposen pushed a commit to eliasposen/goose that referenced this pull request Jan 28, 2026
Signed-off-by: Jonathan Hult <Jonathan@JonathanHult.com>
Signed-off-by: Elias Posen <elias@posen.ch>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants