fix(compaction): configurable summarizer tool_choice; wider overflow detection
Port of upstream grok-build 0.2.105 + 0.2.118. - CompactionToolChoice (auto default | none), resolved env KIGI_COMPACTION_TOOL_CHOICE > [features].compaction_tool_choice > remote settings. Some OpenAI-compatible servers reject tool_choice:"none" with tools attached, failing every long-session compaction; auto keeps them working (the summarization prompt already forbids tool use). Threaded from agent + subagent spawn through CompactionConfig into generate_session_compact; the Responses gate counts hosted tools too, so a hosted-only request still carries the configured choice. - is_context_length_error recognizes the "current message ... exceeds budget" phrasing, so that overflow is Fatal instead of burning the retry budget on a deterministic failure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KSy9S31pZNWXtRZNVJ1sDf
This commit is contained in:
1 parent
6a4bff0d45
commit
1ae803519e
18 files changed
+190
-13
No files matched your search
@@ -1,6 +1,42 @@
|
||||
/// Default auto-compact threshold (% of context window) when no source sets it.
|
||||
pub const DEFAULT_AUTO_COMPACT_THRESHOLD_PERCENT: u8 = 85;
|
||||
|
||||
/// `tool_choice` sent on compaction summarizer requests when tools are
|
||||
/// attached (prefix-cache alignment keeps the tool definitions in the
|
||||
/// request). Default `Auto` because some OpenAI-compatible servers reject
|
||||
/// `tool_choice: "none"`; the summarization prompt itself forbids tool use.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub enum CompactionToolChoice {
|
||||
#[default]
|
||||
Auto,
|
||||
None,
|
||||
}
|
||||
|
||||
impl std::str::FromStr for CompactionToolChoice {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.trim().to_ascii_lowercase().as_str() {
|
||||
"auto" => Ok(Self::Auto),
|
||||
"none" => Ok(Self::None),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const ENV_COMPACTION_TOOL_CHOICE: &str = "KIGI_COMPACTION_TOOL_CHOICE";
|
||||
|
||||
pub(crate) fn resolve_compaction_tool_choice_from(
|
||||
env: Option<&str>,
|
||||
config: Option<&str>,
|
||||
remote: Option<&str>,
|
||||
) -> CompactionToolChoice {
|
||||
env.and_then(|s| s.parse().ok())
|
||||
.or_else(|| config.and_then(|s| s.parse().ok()))
|
||||
.or_else(|| remote.and_then(|s| s.parse().ok()))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Env-var override for `auto_compact_threshold_percent`. Parsed as `u8`;
|
||||
/// out-of-range or unparseable values are ignored.
|
||||
pub(crate) const ENV_AUTO_COMPACT_THRESHOLD_PERCENT: &str = "KIGI_AUTO_COMPACT_THRESHOLD_PERCENT";
|
||||
@@ -127,6 +163,34 @@ pub fn resolve_compaction_wall_clock_budget_secs(gb_global: Option<u64>) -> u64
|
||||
resolved
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod compaction_tool_choice_tests {
|
||||
use super::{CompactionToolChoice, resolve_compaction_tool_choice_from as resolve};
|
||||
|
||||
#[test]
|
||||
fn precedence_env_config_remote_default() {
|
||||
assert_eq!(resolve(None, None, None), CompactionToolChoice::Auto);
|
||||
assert_eq!(
|
||||
resolve(None, None, Some("none")),
|
||||
CompactionToolChoice::None
|
||||
);
|
||||
assert_eq!(
|
||||
resolve(None, Some("auto"), Some("none")),
|
||||
CompactionToolChoice::Auto
|
||||
);
|
||||
assert_eq!(
|
||||
resolve(Some("none"), Some("auto"), Some("auto")),
|
||||
CompactionToolChoice::None
|
||||
);
|
||||
// Unparseable tiers fall through instead of masking lower tiers.
|
||||
assert_eq!(
|
||||
resolve(Some("bogus"), None, Some("none")),
|
||||
CompactionToolChoice::None
|
||||
);
|
||||
assert_eq!(resolve(Some("NONE "), None, None), CompactionToolChoice::None);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod compaction_wall_clock_budget_tests {
|
||||
use super::resolve_compaction_wall_clock_budget_secs as resolve;
|
||||
|
||||
Reference in new issue
Block a user