fix(gateway): respect GOOSE_MAX_TURNS in gateway sessions (#9354)
Signed-off-by: fresh3nough <anonwurcod@proton.me>
This commit is contained in:
@@ -18,6 +18,25 @@ use crate::session::{EnabledExtensionsState, ExtensionState, Session};
|
|||||||
use super::pairing::PairingStore;
|
use super::pairing::PairingStore;
|
||||||
use super::{Gateway, GatewayConfig, IncomingMessage, OutgoingMessage, PairingState, PlatformUser};
|
use super::{Gateway, GatewayConfig, IncomingMessage, OutgoingMessage, PairingState, PlatformUser};
|
||||||
|
|
||||||
|
/// Conservative default cap on tool-calling loops for gateway sessions.
|
||||||
|
///
|
||||||
|
/// Chat platforms like Telegram favor short, snappy replies, so the gateway
|
||||||
|
/// keeps a stricter default than the global `GOOSE_MAX_TURNS` ceiling. Users
|
||||||
|
/// can override this through `GOOSE_GATEWAY_MAX_TURNS` (gateway-specific) or
|
||||||
|
/// `GOOSE_MAX_TURNS` (applies globally).
|
||||||
|
const DEFAULT_GATEWAY_MAX_TURNS: u32 = 5;
|
||||||
|
|
||||||
|
/// Resolve the max turns to use for a gateway session.
|
||||||
|
///
|
||||||
|
/// Precedence: `GOOSE_GATEWAY_MAX_TURNS` -> `GOOSE_MAX_TURNS` ->
|
||||||
|
/// `DEFAULT_GATEWAY_MAX_TURNS`. Extracted as a pure function so the
|
||||||
|
/// precedence rules can be unit-tested without touching the global config.
|
||||||
|
fn resolve_gateway_max_turns(gateway_override: Option<u32>, global_max_turns: Option<u32>) -> u32 {
|
||||||
|
gateway_override
|
||||||
|
.or(global_max_turns)
|
||||||
|
.unwrap_or(DEFAULT_GATEWAY_MAX_TURNS)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GatewayHandler {
|
pub struct GatewayHandler {
|
||||||
agent_manager: Arc<AgentManager>,
|
agent_manager: Arc<AgentManager>,
|
||||||
@@ -316,12 +335,20 @@ impl GatewayHandler {
|
|||||||
// dozens of tool calls before responding. After this many
|
// dozens of tool calls before responding. After this many
|
||||||
// LLM→tool round-trips the agent will stop and reply with
|
// LLM→tool round-trips the agent will stop and reply with
|
||||||
// whatever it has.
|
// whatever it has.
|
||||||
const GATEWAY_MAX_TURNS: u32 = 5;
|
//
|
||||||
|
// Honors `GOOSE_GATEWAY_MAX_TURNS` (gateway-specific override) and
|
||||||
|
// `GOOSE_MAX_TURNS` (global), falling back to a conservative default
|
||||||
|
// so the limit is configurable without editing the source.
|
||||||
|
let config = Config::global();
|
||||||
|
let max_turns = resolve_gateway_max_turns(
|
||||||
|
config.get_param::<u32>("GOOSE_GATEWAY_MAX_TURNS").ok(),
|
||||||
|
config.get_param::<u32>("GOOSE_MAX_TURNS").ok(),
|
||||||
|
);
|
||||||
|
|
||||||
let session_config = SessionConfig {
|
let session_config = SessionConfig {
|
||||||
id: session_id.to_string(),
|
id: session_id.to_string(),
|
||||||
schedule_id: None,
|
schedule_id: None,
|
||||||
max_turns: Some(GATEWAY_MAX_TURNS),
|
max_turns: Some(max_turns),
|
||||||
retry_config: None,
|
retry_config: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -509,3 +536,31 @@ fn gateway_working_dir(platform: &str, user_id: &str) -> PathBuf {
|
|||||||
.join(platform)
|
.join(platform)
|
||||||
.join(user_id)
|
.join(user_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn defaults_when_no_overrides() {
|
||||||
|
assert_eq!(
|
||||||
|
resolve_gateway_max_turns(None, None),
|
||||||
|
DEFAULT_GATEWAY_MAX_TURNS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn uses_global_max_turns_when_gateway_unset() {
|
||||||
|
assert_eq!(resolve_gateway_max_turns(None, Some(42)), 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gateway_override_wins_over_global() {
|
||||||
|
assert_eq!(resolve_gateway_max_turns(Some(10), Some(42)), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gateway_override_used_when_global_unset() {
|
||||||
|
assert_eq!(resolve_gateway_max_turns(Some(25), None), 25);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ These variables control how goose manages conversation sessions and context.
|
|||||||
|----------|---------|---------|---------|
|
|----------|---------|---------|---------|
|
||||||
| `GOOSE_CONTEXT_STRATEGY` | Controls how goose handles context limit exceeded situations | "summarize", "truncate", "clear", "prompt" | "prompt" (interactive), "summarize" (headless) |
|
| `GOOSE_CONTEXT_STRATEGY` | Controls how goose handles context limit exceeded situations | "summarize", "truncate", "clear", "prompt" | "prompt" (interactive), "summarize" (headless) |
|
||||||
| `GOOSE_MAX_TURNS` | [Maximum number of turns](/docs/guides/sessions/smart-context-management#maximum-turns) allowed without user input | Integer (e.g., 10, 50, 100) | 1000 |
|
| `GOOSE_MAX_TURNS` | [Maximum number of turns](/docs/guides/sessions/smart-context-management#maximum-turns) allowed without user input | Integer (e.g., 10, 50, 100) | 1000 |
|
||||||
|
| `GOOSE_GATEWAY_MAX_TURNS` | Maximum number of turns for gateway sessions (e.g., Telegram). Overrides `GOOSE_MAX_TURNS` for gateway traffic only, so chat platforms can keep a stricter cap than CLI/desktop sessions. | Integer (e.g., 5, 10, 25) | Falls back to `GOOSE_MAX_TURNS`, then 5 |
|
||||||
| `GOOSE_SUBAGENT_MAX_TURNS` | Sets the maximum turns allowed for a [subagent](/docs/guides/context-engineering/subagents) to complete before timeout. Can be overridden by [`settings.max_turns`](/docs/guides/recipes/recipe-reference#settings) in recipes or subagent tool calls. | Integer (e.g., 25) | 25 |
|
| `GOOSE_SUBAGENT_MAX_TURNS` | Sets the maximum turns allowed for a [subagent](/docs/guides/context-engineering/subagents) to complete before timeout. Can be overridden by [`settings.max_turns`](/docs/guides/recipes/recipe-reference#settings) in recipes or subagent tool calls. | Integer (e.g., 25) | 25 |
|
||||||
| `GOOSE_MAX_BACKGROUND_TASKS` | Sets the maximum number of concurrent background [subagent](/docs/guides/context-engineering/subagents) tasks goose can run at once | Integer (e.g., 1, 5, 10) | 5 |
|
| `GOOSE_MAX_BACKGROUND_TASKS` | Sets the maximum number of concurrent background [subagent](/docs/guides/context-engineering/subagents) tasks goose can run at once | Integer (e.g., 1, 5, 10) | 5 |
|
||||||
| `CONTEXT_FILE_NAMES` | Specifies custom filenames for [hint/context files](/docs/guides/context-engineering/using-goosehints#custom-context-files) | JSON array of strings (e.g., `["CLAUDE.md", ".goosehints"]`) | `[".goosehints"]` |
|
| `CONTEXT_FILE_NAMES` | Specifies custom filenames for [hint/context files](/docs/guides/context-engineering/using-goosehints#custom-context-files) | JSON array of strings (e.g., `["CLAUDE.md", ".goosehints"]`) | `[".goosehints"]` |
|
||||||
@@ -268,6 +269,10 @@ export GOOSE_MAX_TURNS=25
|
|||||||
# Set a reasonable limit for production
|
# Set a reasonable limit for production
|
||||||
export GOOSE_MAX_TURNS=100
|
export GOOSE_MAX_TURNS=100
|
||||||
|
|
||||||
|
# Raise the per-gateway cap without changing CLI/desktop limits
|
||||||
|
# (applies to Telegram and other gateway sessions only)
|
||||||
|
export GOOSE_GATEWAY_MAX_TURNS=15
|
||||||
|
|
||||||
# Customize the default subagent turn limit
|
# Customize the default subagent turn limit
|
||||||
# Note: This can be overridden per-recipe or per-subagent using the max_turns setting
|
# Note: This can be overridden per-recipe or per-subagent using the max_turns setting
|
||||||
export GOOSE_SUBAGENT_MAX_TURNS=50
|
export GOOSE_SUBAGENT_MAX_TURNS=50
|
||||||
|
|||||||
Reference in New Issue
Block a user