feat: compact worker サーキットブレーカーを占有量ベースに統一

This commit is contained in:
2026-05-11 00:43:16 +09:00
parent d6f27f7c45
commit 8100a5dfd1
10 changed files with 246 additions and 29 deletions
+38 -1
View File
@@ -116,6 +116,8 @@ pub struct CompactionConfigPartial {
#[serde(default)]
pub compact_worker_max_input_tokens: Option<u64>,
#[serde(default)]
pub compact_worker_max_turns: Option<u32>,
#[serde(default)]
pub model: Option<ModelManifest>,
}
@@ -325,6 +327,9 @@ impl CompactionConfigPartial {
compact_worker_max_input_tokens: upper
.compact_worker_max_input_tokens
.or(self.compact_worker_max_input_tokens),
compact_worker_max_turns: upper
.compact_worker_max_turns
.or(self.compact_worker_max_turns),
model: merge_option(self.model, upper.model, ModelManifest::merge),
}
}
@@ -461,6 +466,9 @@ impl TryFrom<PodManifestConfig> for PodManifest {
compact_worker_max_input_tokens: c
.compact_worker_max_input_tokens
.unwrap_or(defaults::COMPACT_WORKER_MAX_INPUT_TOKENS),
compact_worker_max_turns: c
.compact_worker_max_turns
.or(defaults::COMPACT_WORKER_MAX_TURNS),
model: c.model,
})
})
@@ -949,6 +957,32 @@ stop_sequences = ["\n\n", "</stop>"]
);
}
#[test]
fn from_toml_accepts_compact_worker_max_turns() {
let cfg = PodManifestConfig::from_toml(
r#"
[compaction]
compact_worker_max_turns = 7
"#,
)
.unwrap();
assert_eq!(cfg.compaction.unwrap().compact_worker_max_turns, Some(7));
}
#[test]
fn try_from_compaction_defaults_compact_worker_max_turns() {
let mut cfg = minimal_valid();
cfg.compaction = Some(CompactionConfigPartial::default());
let manifest = PodManifest::try_from(cfg).unwrap();
assert_eq!(
manifest.compaction.unwrap().compact_worker_max_turns,
defaults::COMPACT_WORKER_MAX_TURNS
);
}
#[test]
fn from_toml_partial_layer_succeeds() {
// A project-layer manifest with only scope set must parse fine.
@@ -1042,7 +1076,10 @@ name = "dbg"
fn skills_directories_resolved_against_base() {
let mut cfg = minimal_valid();
cfg.skills = Some(SkillsConfig {
directories: vec![PathBuf::from(".claude/skills"), PathBuf::from("/abs/elsewhere")],
directories: vec![
PathBuf::from(".claude/skills"),
PathBuf::from("/abs/elsewhere"),
],
});
let resolved = cfg.resolve_paths(Path::new("/workspace/proj"));
let dirs = resolved.skills.as_ref().unwrap().directories.clone();
+5 -1
View File
@@ -36,12 +36,16 @@ pub const DEFAULT_INSTRUCTION: &str = "$insomnia/default";
/// [`crate::CompactionConfig::compact_auto_read_budget`].
pub const COMPACT_AUTO_READ_BUDGET: u64 = 8000;
/// Cumulative input-token cap for the compact worker's own LLM
/// Current prompt-occupancy cap for the compact worker's own LLM
/// calls. Exceeding this aborts the compact run (circuit-breaker
/// path). See
/// [`crate::CompactionConfig::compact_worker_max_input_tokens`].
pub const COMPACT_WORKER_MAX_INPUT_TOKENS: u64 = 50_000;
/// Optional maximum compact-worker tool-loop depth. `None` means unlimited.
/// See [`crate::CompactionConfig::compact_worker_max_turns`].
pub const COMPACT_WORKER_MAX_TURNS: Option<u32> = Some(20);
/// Number of recently-touched files fed to the compact worker as
/// default references.
pub const COMPACT_DEFAULT_REFERENCE_COUNT: usize = 5;
+24 -2
View File
@@ -321,11 +321,16 @@ pub struct CompactionConfig {
#[serde(default = "default_compact_auto_read_budget")]
pub compact_auto_read_budget: u64,
/// Cumulative input-token cap for the compact worker's own LLM
/// calls. Exceeding this aborts the compact run.
/// Current prompt-occupancy cap for the compact worker's own LLM
/// requests. Exceeding this aborts the compact run.
#[serde(default = "default_compact_worker_max_input_tokens")]
pub compact_worker_max_input_tokens: u64,
/// Optional maximum compact-worker tool-loop depth. `None` leaves the
/// worker unlimited; the default bounds runaway short-context loops.
#[serde(default = "default_compact_worker_max_turns")]
pub compact_worker_max_turns: Option<u32>,
/// Optional model for the compactor (summary) LLM.
/// If omitted, the main model is cloned via `clone_boxed()`.
#[serde(default)]
@@ -347,6 +352,9 @@ fn default_compact_auto_read_budget() -> u64 {
fn default_compact_worker_max_input_tokens() -> u64 {
defaults::COMPACT_WORKER_MAX_INPUT_TOKENS
}
fn default_compact_worker_max_turns() -> Option<u32> {
defaults::COMPACT_WORKER_MAX_TURNS
}
impl Default for CompactionConfig {
fn default() -> Self {
@@ -358,6 +366,7 @@ impl Default for CompactionConfig {
compact_retained_tokens: default_compact_retained_tokens(),
compact_auto_read_budget: default_compact_auto_read_budget(),
compact_worker_max_input_tokens: default_compact_worker_max_input_tokens(),
compact_worker_max_turns: default_compact_worker_max_turns(),
model: None,
}
}
@@ -521,6 +530,19 @@ model_id = "claude-sonnet-4-20250514"
assert_eq!(c.compact_threshold, Some(80000));
assert_eq!(c.compact_request_threshold, None);
assert_eq!(c.compact_retained_tokens, 8000);
assert_eq!(c.compact_worker_max_turns, Some(20));
}
#[test]
fn parse_compaction_worker_max_turns() {
let toml = format!(
"{MINIMAL_REQUIRED}\n\
[compaction]\n\
compact_worker_max_turns = 7\n"
);
let manifest = PodManifest::from_toml(&toml).unwrap();
let c = manifest.compaction.unwrap();
assert_eq!(c.compact_worker_max_turns, Some(7));
}
#[test]