use serde::{Deserialize, Serialize};
use crate::constants::defaults;
use crate::constants::tool_limits;
use super::approval::{AsyncApprovalConfig, ConfidenceEscalationConfig, SkepticPanelConfig};
use super::{ContextResetMode, ContinuationPolicy, HarnessOrchestrationMode};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct AgentHarnessConfig {
#[serde(default = "default_harness_max_tool_calls_per_turn")]
pub max_tool_calls_per_turn: usize,
#[serde(default = "default_harness_max_tool_wall_clock_secs")]
pub max_tool_wall_clock_secs: u64,
#[serde(default = "default_harness_max_tool_retries")]
pub max_tool_retries: u32,
#[serde(default = "default_harness_max_parallel_tool_calls")]
pub max_parallel_tool_calls: usize,
#[serde(default = "default_harness_auto_compaction_enabled")]
pub auto_compaction_enabled: bool,
#[serde(default)]
pub auto_compaction_threshold_tokens: Option<u64>,
#[serde(default)]
pub auto_compaction_instructions: Option<String>,
#[serde(default)]
pub auto_compaction_pause_after: bool,
#[serde(default = "default_harness_compact_on_model_switch")]
pub compact_on_model_switch: bool,
#[serde(default)]
pub tool_result_clearing: ToolResultClearingConfig,
#[serde(default)]
pub max_budget_usd: Option<f64>,
#[serde(default = "default_harness_budget_warning_threshold")]
pub budget_warning_threshold: f64,
#[serde(default)]
pub continuation_policy: ContinuationPolicy,
#[serde(default)]
pub context_reset_mode: ContextResetMode,
#[serde(default = "default_harness_context_reset_stall_threshold")]
pub context_reset_stall_threshold: u32,
#[serde(default)]
pub event_log_path: Option<String>,
#[serde(default)]
pub orchestration_mode: HarnessOrchestrationMode,
#[serde(default = "default_harness_max_revision_rounds")]
pub max_revision_rounds: usize,
#[serde(default)]
pub confidence_escalation: ConfidenceEscalationConfig,
#[serde(default)]
async_approval: AsyncApprovalConfig,
#[serde(default)]
pub skeptic_panel: SkepticPanelConfig,
#[serde(default)]
pub verification: VerificationAutoRecoveryConfig,
#[serde(default)]
pub continuation: TrackerContinuationConfig,
}
impl Default for AgentHarnessConfig {
fn default() -> Self {
Self {
max_tool_calls_per_turn: default_harness_max_tool_calls_per_turn(),
max_tool_wall_clock_secs: default_harness_max_tool_wall_clock_secs(),
max_tool_retries: default_harness_max_tool_retries(),
max_parallel_tool_calls: default_harness_max_parallel_tool_calls(),
auto_compaction_enabled: default_harness_auto_compaction_enabled(),
auto_compaction_threshold_tokens: None,
auto_compaction_instructions: None,
auto_compaction_pause_after: false,
compact_on_model_switch: default_harness_compact_on_model_switch(),
tool_result_clearing: ToolResultClearingConfig::default(),
max_budget_usd: None,
budget_warning_threshold: default_harness_budget_warning_threshold(),
continuation_policy: ContinuationPolicy::default(),
context_reset_mode: ContextResetMode::default(),
context_reset_stall_threshold: default_harness_context_reset_stall_threshold(),
event_log_path: None,
orchestration_mode: HarnessOrchestrationMode::default(),
max_revision_rounds: default_harness_max_revision_rounds(),
confidence_escalation: ConfidenceEscalationConfig::default(),
async_approval: AsyncApprovalConfig::default(),
skeptic_panel: SkepticPanelConfig::default(),
verification: VerificationAutoRecoveryConfig::default(),
continuation: TrackerContinuationConfig::default(),
}
}
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct TrackerContinuationConfig {
#[serde(default = "default_tracker_auto_continue")]
pub auto_continue_tracker: bool,
#[serde(default = "default_tracker_cross_turn_turns")]
pub cross_turn_turns: u8,
}
impl Default for TrackerContinuationConfig {
fn default() -> Self {
Self {
auto_continue_tracker: default_tracker_auto_continue(),
cross_turn_turns: default_tracker_cross_turn_turns(),
}
}
}
#[inline]
const fn default_tracker_auto_continue() -> bool {
true
}
#[inline]
const fn default_tracker_cross_turn_turns() -> u8 {
32
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct VerificationAutoRecoveryConfig {
#[serde(default = "default_verification_auto_execute")]
pub auto_execute: bool,
#[serde(default = "default_verification_in_turn_attempts")]
pub in_turn_attempts: u8,
#[serde(default = "default_verification_cross_turn_turns")]
pub cross_turn_turns: u8,
#[serde(default)]
pub default_verifier_override: Option<String>,
#[serde(default = "default_verification_max_consecutive_failures")]
pub max_consecutive_failures: u8,
}
impl Default for VerificationAutoRecoveryConfig {
fn default() -> Self {
Self {
auto_execute: default_verification_auto_execute(),
in_turn_attempts: default_verification_in_turn_attempts(),
cross_turn_turns: default_verification_cross_turn_turns(),
default_verifier_override: None,
max_consecutive_failures: default_verification_max_consecutive_failures(),
}
}
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ToolResultClearingConfig {
#[serde(default = "default_tool_result_clearing_enabled")]
pub enabled: bool,
#[serde(default = "default_tool_result_clearing_trigger_tokens")]
pub trigger_tokens: u64,
#[serde(default = "default_tool_result_clearing_keep_tool_uses")]
pub keep_tool_uses: u32,
#[serde(default = "default_tool_result_clearing_clear_at_least_tokens")]
pub clear_at_least_tokens: u64,
#[serde(default = "default_tool_result_clearing_clear_tool_inputs")]
pub clear_tool_inputs: bool,
}
impl Default for ToolResultClearingConfig {
fn default() -> Self {
Self {
enabled: default_tool_result_clearing_enabled(),
trigger_tokens: default_tool_result_clearing_trigger_tokens(),
keep_tool_uses: default_tool_result_clearing_keep_tool_uses(),
clear_at_least_tokens: default_tool_result_clearing_clear_at_least_tokens(),
clear_tool_inputs: default_tool_result_clearing_clear_tool_inputs(),
}
}
}
impl ToolResultClearingConfig {
pub(crate) fn validate(&self) -> Result<(), String> {
if self.trigger_tokens == 0 {
return Err("tool_result_clearing.trigger_tokens must be greater than 0".to_string());
}
if self.keep_tool_uses == 0 {
return Err("tool_result_clearing.keep_tool_uses must be greater than 0".to_string());
}
if self.clear_at_least_tokens == 0 {
return Err("tool_result_clearing.clear_at_least_tokens must be greater than 0".to_string());
}
Ok(())
}
}
#[inline]
const fn default_harness_max_tool_calls_per_turn() -> usize {
tool_limits::DEFAULT_MAX_TOOL_CALLS_PER_TURN
}
#[inline]
const fn default_harness_max_tool_wall_clock_secs() -> u64 {
defaults::DEFAULT_MAX_TOOL_WALL_CLOCK_SECS
}
#[inline]
const fn default_harness_max_tool_retries() -> u32 {
defaults::DEFAULT_MAX_TOOL_RETRIES
}
#[inline]
const fn default_harness_max_parallel_tool_calls() -> usize {
4 }
#[inline]
const fn default_harness_auto_compaction_enabled() -> bool {
true
}
const fn default_harness_compact_on_model_switch() -> bool {
true
}
#[inline]
const fn default_harness_context_reset_stall_threshold() -> u32 {
2
}
#[inline]
const fn default_verification_auto_execute() -> bool {
true
}
#[inline]
const fn default_verification_in_turn_attempts() -> u8 {
2
}
#[inline]
const fn default_verification_cross_turn_turns() -> u8 {
2
}
#[inline]
const fn default_verification_max_consecutive_failures() -> u8 {
3
}
#[inline]
const fn default_tool_result_clearing_enabled() -> bool {
true
}
#[inline]
const fn default_tool_result_clearing_trigger_tokens() -> u64 {
40_000
}
#[inline]
const fn default_tool_result_clearing_keep_tool_uses() -> u32 {
2
}
#[inline]
const fn default_tool_result_clearing_clear_at_least_tokens() -> u64 {
30_000
}
#[inline]
const fn default_tool_result_clearing_clear_tool_inputs() -> bool {
true
}
#[inline]
const fn default_harness_max_revision_rounds() -> usize {
2
}
#[inline]
const fn default_harness_budget_warning_threshold() -> f64 {
0.75
}