diff --git a/crates/zeroclaw-channels/src/orchestrator/mod.rs b/crates/zeroclaw-channels/src/orchestrator/mod.rs index 0e95aeb3c7..196b65ff62 100644 --- a/crates/zeroclaw-channels/src/orchestrator/mod.rs +++ b/crates/zeroclaw-channels/src/orchestrator/mod.rs @@ -11810,6 +11810,7 @@ This is an example JSON object for profile settings."#; ack_reactions: None, proxy_url: None, approval_timeout_secs: 120, + reply_min_interval_secs: 0, }); match build_channel_by_id(&config, "telegram") { Ok(channel) => assert_eq!(channel.name(), "telegram"), diff --git a/crates/zeroclaw-config/src/schema.rs b/crates/zeroclaw-config/src/schema.rs index e088f75272..6a5c92a0b3 100644 --- a/crates/zeroclaw-config/src/schema.rs +++ b/crates/zeroclaw-config/src/schema.rs @@ -7065,6 +7065,17 @@ pub struct TelegramConfig { /// button on a tool approval prompt before auto-denying. Default: 120. #[serde(default = "default_telegram_approval_timeout_secs")] pub approval_timeout_secs: u64, + /// Minimum wall-clock interval (seconds) between consecutive outbound + /// agent replies on this channel. `0` (default) preserves the current + /// behaviour where replies fire as soon as the LLM completes. The + /// intended range is `0..=3600`. + /// + /// On paired-identity channels under personal accounts, sub-second + /// replies are a strong AI-tell and a platform-side anomaly signal; + /// raising this value paces the agent so its cadence resembles a + /// human operator's. + #[serde(default)] + pub reply_min_interval_secs: u64, } impl ChannelConfig for TelegramConfig { @@ -12327,6 +12338,7 @@ auto_save = true ack_reactions: None, proxy_url: None, approval_timeout_secs: default_telegram_approval_timeout_secs(), + reply_min_interval_secs: 0, }), discord: None, discord_history: None, @@ -13232,6 +13244,7 @@ default_temperature = 0.7 ack_reactions: None, proxy_url: None, approval_timeout_secs: 120, + reply_min_interval_secs: 0, }; let json = serde_json::to_string(&tc).unwrap(); let parsed: TelegramConfig = serde_json::from_str(&json).unwrap(); @@ -16654,6 +16667,7 @@ require_otp_to_resume = true ack_reactions: None, proxy_url: None, approval_timeout_secs: default_telegram_approval_timeout_secs(), + reply_min_interval_secs: 0, }); // Save (triggers encryption) diff --git a/crates/zeroclaw-runtime/src/daemon/mod.rs b/crates/zeroclaw-runtime/src/daemon/mod.rs index f2a3fee5ed..2db34a00ef 100644 --- a/crates/zeroclaw-runtime/src/daemon/mod.rs +++ b/crates/zeroclaw-runtime/src/daemon/mod.rs @@ -1115,6 +1115,7 @@ mod tests { ack_reactions: None, proxy_url: None, approval_timeout_secs: 120, + reply_min_interval_secs: 0, }); assert!(has_supervised_channels(&config)); } @@ -1261,6 +1262,7 @@ mod tests { ack_reactions: None, proxy_url: None, approval_timeout_secs: 120, + reply_min_interval_secs: 0, }); let target = resolve_heartbeat_delivery(&config).unwrap(); @@ -1281,6 +1283,7 @@ mod tests { ack_reactions: None, proxy_url: None, approval_timeout_secs: 120, + reply_min_interval_secs: 0, }); let target = resolve_heartbeat_delivery(&config).unwrap(); diff --git a/crates/zeroclaw-runtime/src/integrations/registry.rs b/crates/zeroclaw-runtime/src/integrations/registry.rs index a7cbb0833d..051037b623 100644 --- a/crates/zeroclaw-runtime/src/integrations/registry.rs +++ b/crates/zeroclaw-runtime/src/integrations/registry.rs @@ -880,6 +880,7 @@ mod tests { ack_reactions: None, proxy_url: None, approval_timeout_secs: 120, + reply_min_interval_secs: 0, }); let entries = all_integrations(); let tg = entries.iter().find(|e| e.name == "Telegram").unwrap(); diff --git a/src/config/mod.rs b/src/config/mod.rs index 783e7f6e0f..f23b068847 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -81,6 +81,7 @@ mod tests { ack_reactions: None, proxy_url: None, approval_timeout_secs: 120, + reply_min_interval_secs: 0, }; let discord = DiscordConfig {