compactの実装

This commit is contained in:
2026-04-12 07:09:48 +09:00
parent 47c59a416e
commit bcc7faa0ba
19 changed files with 439 additions and 21 deletions
+111
View File
@@ -18,6 +18,8 @@ pub struct PodManifest {
pub worker: WorkerManifest,
#[serde(default)]
pub scope: Option<ScopeConfig>,
#[serde(default)]
pub compaction: Option<CompactionConfig>,
}
/// Pod metadata.
@@ -83,6 +85,50 @@ pub struct ScopeConfig {
pub root: PathBuf,
}
/// Context compaction configuration.
///
/// Controls Prune (content removal from old tool results) and Compact
/// (full history summarisation). Omitting `[compaction]` disables both.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompactionConfig {
/// Number of recent turns protected from pruning.
#[serde(default = "default_prune_protected_turns")]
pub prune_protected_turns: usize,
/// Minimum estimated token savings to trigger a prune.
#[serde(default = "default_prune_min_savings")]
pub prune_min_savings: usize,
/// When `input_tokens` exceeds this, run compact. `None` = compact disabled.
#[serde(default)]
pub compact_threshold: Option<u64>,
/// Number of recent turns retained after compaction.
#[serde(default = "default_compact_retained_turns")]
pub compact_retained_turns: usize,
/// Optional provider for the compactor (summary) LLM.
/// If omitted, the main provider is cloned via `clone_boxed()`.
#[serde(default)]
pub provider: Option<ProviderConfig>,
}
fn default_prune_protected_turns() -> usize { 3 }
fn default_prune_min_savings() -> usize { 4096 }
fn default_compact_retained_turns() -> usize { 2 }
impl Default for CompactionConfig {
fn default() -> Self {
Self {
prune_protected_turns: default_prune_protected_turns(),
prune_min_savings: default_prune_min_savings(),
compact_threshold: None,
compact_retained_turns: default_compact_retained_turns(),
provider: None,
}
}
}
impl PodManifest {
/// Parse a manifest from a TOML string.
pub fn from_toml(s: &str) -> Result<Self, toml::de::Error> {
@@ -218,6 +264,71 @@ max_turns = 0
assert!(PodManifest::from_toml(toml).is_err());
}
#[test]
fn parse_compaction_config() {
let toml = r#"
[pod]
name = "test"
[provider]
kind = "anthropic"
model = "claude-sonnet-4-20250514"
[worker]
[compaction]
compact_threshold = 80000
"#;
let manifest = PodManifest::from_toml(toml).unwrap();
let c = manifest.compaction.unwrap();
assert_eq!(c.prune_protected_turns, 3);
assert_eq!(c.prune_min_savings, 4096);
assert_eq!(c.compact_threshold, Some(80000));
assert_eq!(c.compact_retained_turns, 2);
}
#[test]
fn parse_compaction_with_provider() {
let toml = r#"
[pod]
name = "test"
[provider]
kind = "anthropic"
model = "claude-sonnet-4-20250514"
[worker]
[compaction]
compact_threshold = 80000
[compaction.provider]
kind = "gemini"
model = "gemini-2.0-flash"
"#;
let manifest = PodManifest::from_toml(toml).unwrap();
let c = manifest.compaction.unwrap();
let p = c.provider.unwrap();
assert_eq!(p.kind, ProviderKind::Gemini);
assert_eq!(p.model, "gemini-2.0-flash");
}
#[test]
fn omitted_compaction_is_none() {
let toml = r#"
[pod]
name = "test"
[provider]
kind = "anthropic"
model = "claude-sonnet-4-20250514"
[worker]
"#;
let manifest = PodManifest::from_toml(toml).unwrap();
assert!(manifest.compaction.is_none());
}
#[test]
fn reject_unknown_provider() {
let toml = r#"