Skip to content

Commit 155365e

Browse files
committed
feat(query): add degradationSummaryEnabled config toggle
Add a config setting 'degradationSummaryEnabled' (default: true) that controls the max-steps graceful degradation system. When disabled, the agent returns cold on hitting the turn limit instead of injecting a forced summary turn.
1 parent 00db2b6 commit 155365e

3 files changed

Lines changed: 31 additions & 0 deletions

File tree

src-rust/crates/core/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,12 @@ pub mod config {
11141114
/// Keyboard scrolling (PageUp/PageDown, etc.) is unaffected either way.
11151115
#[serde(default, rename = "mouseCapture", skip_serializing_if = "Option::is_none")]
11161116
pub mouse_capture: Option<bool>,
1117+
/// Whether the max-steps graceful degradation summary turn is enabled.
1118+
/// When `true` (default), exceeding `max_turns` runs one final
1119+
/// tool-less turn asking the model to summarize progress. When `false`,
1120+
/// the loop returns cold (last assistant message) immediately.
1121+
#[serde(default = "default_true", rename = "degradationSummaryEnabled")]
1122+
pub degradation_summary_enabled: bool,
11171123
}
11181124

11191125
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
@@ -1982,6 +1988,7 @@ pub mod config {
19821988
file_injection_enabled: over.config.file_injection_enabled || base.config.file_injection_enabled,
19831989
file_injection_max_size: if over.config.file_injection_max_size != 0 { over.config.file_injection_max_size } else { base.config.file_injection_max_size },
19841990
request_timeout_secs: over.config.request_timeout_secs.or(base.config.request_timeout_secs),
1991+
degradation_summary_enabled: over.config.degradation_summary_enabled && base.config.degradation_summary_enabled,
19851992
};
19861993
Self {
19871994
config: merged_config,

src-rust/crates/query/src/agent_tool.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ impl Tool for AgentTool {
372372
// Sub-agents run to their own completion and never drive goal
373373
// continuation — stop after one turn like every non-goal run.
374374
continuation: crate::continuation::ContinuationMode::Default,
375+
degradation_enabled: true,
375376
};
376377
// -----------------------------------------------------------------------
377378
// Background mode: spawn and return agent_id immediately.

src-rust/crates/query/src/lib.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ pub struct QueryConfig {
9595
pub model: String,
9696
pub max_tokens: u32,
9797
pub max_turns: u32,
98+
/// Whether the max-steps graceful degradation summary turn is enabled.
99+
/// When `false`, exceeding `max_turns` returns cold (last assistant
100+
/// message) instead of running a final tool-less summary turn.
101+
pub degradation_enabled: bool,
98102
pub system_prompt: Option<String>,
99103
pub append_system_prompt: Option<String>,
100104
pub output_style: claurst_core::system_prompt::OutputStyle,
@@ -174,6 +178,7 @@ impl Default for QueryConfig {
174178
model: claurst_core::constants::DEFAULT_MODEL.to_string(),
175179
max_tokens: claurst_core::constants::DEFAULT_MAX_TOKENS,
176180
max_turns: claurst_core::constants::MAX_TURNS_DEFAULT,
181+
degradation_enabled: true,
177182
system_prompt: None,
178183
append_system_prompt: None,
179184
output_style: claurst_core::system_prompt::OutputStyle::Default,
@@ -210,6 +215,7 @@ impl QueryConfig {
210215
.as_ref()
211216
.map(|p| p.display().to_string()),
212217
managed_agents: cfg.managed_agents.clone(),
218+
degradation_enabled: cfg.degradation_summary_enabled,
213219
..Default::default()
214220
}
215221
}
@@ -231,6 +237,7 @@ impl QueryConfig {
231237
.as_ref()
232238
.map(|p| p.display().to_string()),
233239
managed_agents: cfg.managed_agents.clone(),
240+
degradation_enabled: cfg.degradation_summary_enabled,
234241
..Default::default()
235242
}
236243
}
@@ -471,6 +478,21 @@ pub async fn run_query_loop(
471478
// dispatched exactly once, and re-exceeding the cap afterwards returns
472479
// cold. Applies to both goal and non-goal runs.
473480
let degradation_turn = if turn > effective_max_turns {
481+
if !config.degradation_enabled {
482+
info!(
483+
turns = turn,
484+
max = effective_max_turns,
485+
"Max turns reached — degradation disabled, returning cold"
486+
);
487+
let last_msg = messages
488+
.last()
489+
.cloned()
490+
.unwrap_or_else(|| Message::assistant("Max turns reached."));
491+
return QueryOutcome::EndTurn {
492+
message: last_msg,
493+
usage: UsageInfo::default(),
494+
};
495+
}
474496
if degradation_done {
475497
info!(
476498
turns = turn,
@@ -2127,6 +2149,7 @@ mod tests {
21272149
model: "claude-sonnet-4-6".to_string(),
21282150
max_tokens: 4096,
21292151
max_turns: 10,
2152+
degradation_enabled: true,
21302153
system_prompt: sys.map(String::from),
21312154
append_system_prompt: append.map(String::from),
21322155
output_style: claurst_core::system_prompt::OutputStyle::Default,

0 commit comments

Comments
 (0)